C语言实现单链表,并完成链表常用API函数:

  1.链表增、删、改、查。

  2.打印链表、反转打印、打印环形链表。

  3.链表排序、链表冒泡排序、链表快速排序。

  4.求链表节点个数(普通方法、递归方法)。

  5.链表反转(普通方法、递归方法)。

  6.链表合并。

  7.获取链表中间节点。

  8.判断链表是否有环。

LinkList.h :

 #include <stdio.h>
#include <stdlib.h> struct LinkNode
{
int data;
struct LinkNode *pNext;
}; typedef struct LinkNode Node; //简化类型 void init(Node *phead); //初始化
Node *addBack(Node *phead, int data); //尾插法:尾部添加节点
void addHead(Node *phead, int data); //头插法:头部添加节点 void ShowAll(Node *phead); //显示链表
void revShowAll(Node *phead); //反转显示链表
void ShowCircleLink(Node *phead); //显示环形链表 Node *searchFirst(Node *phead, int findData); //查找 Node *changeFirst(Node *phead, int findData, int newData); //修改 Node *delFirst(Node *phead, int delData); //删除 Node *insertFirst(Node *phead, int insertData,int newData); //插入 void bubbleSort(Node *phead); //冒泡排序 void quickSort(Node *pbegin, Node *pback); //快速排序法:(双冒泡)
Node *fen(Node *pbegin, Node *pback); //分段 int getNum1(Node *phead); //求链表节点个数
int getNum2(Node *phead); //求链表节点个数(递归) Node *revList1(Node *phead); //链表反转(普通方法)
Node *revList2(Node *phead); //链表反转(递归方法) //将链表phead1和phead2合并到phead3,并返回链表phead3
Node *mergeList(Node *phead3, Node *phead1, Node *phead2); //链表合并 Node *getMid(Node *phead); //获取链表的中间节点 int judgeCircle(Node *phead); //判断链表是否有环

LinkList.c :

 #include "LinkList.h"

 //初始化
void init(Node *phead)
{
phead->pNext = NULL;
phead->data = ;
} //显示链表
void ShowAll(Node *phead)
{
if (phead == NULL)
return;
else
{
printf("%4d", phead->data);
//printf("%d,%p,%p\n", phead->data, phead, phead->pNext);
ShowAll(phead->pNext); //跳到下一个节点 }
} //反转显示链表
void revShowAll(Node *phead)
{
if (phead == NULL)
return;
else
{
printf("%d,%p,%p\n", phead->data, phead, phead->pNext);
ShowAll(phead->pNext); //跳到下一个节点 }
} //显示环形链表
void ShowCircleLink(Node *phead)
{
if (phead == NULL)
return;
else
{
Node *p = phead;
for (; p->pNext != phead; p = p->pNext)
printf("%4d", p->data); printf("%4d", p->data); //还需要再打印最后一个元素 }
} //尾插法:尾部添加节点 (改变了头指针,改变一个指针,要么二级指针,要么用返回值给指针赋值,这里采用返回值)
Node *addBack(Node *phead, int data)
{
Node *pnew = malloc(sizeof(Node)); //构建新的节点
pnew->data = data; //新节点赋值
pnew->pNext = NULL; if (phead == NULL) //phead为空,直接连接
phead = pnew;
else
{
Node *ptemp = phead; //备份一下头指针
while (ptemp->pNext != NULL)
{
ptemp = ptemp -> pNext; //循环前进
}
ptemp->pNext = pnew; //链接
} return phead;
} //头插法:头部添加节点 (采用二级指针的方法)
void addHead(Node **pphead, int data)
{
Node *pnew = malloc(sizeof(Node)); //构建新的节点
pnew->data = data; //新节点赋值
pnew->pNext = NULL; if(*pphead==NULL)
pphead = pnew;
else
{
pnew->pNext = *pphead;
*pphead = pnew;
}
} //查找
Node *searchFirst(Node *phead, int findData)
{
for (Node *p = phead; p != NULL; p = p->pNext)
{
if (p->data == findData)
{
return p; //返回找到的指针位置
}
} return NULL;
} //修改
Node *changeFirst(Node *phead, int findData, int newData)
{
for (Node *p = phead; p != NULL; p = p->pNext)
{
if (p->data == findData)
{
p->data = newData;
return p; //返回找到的指针位置
}
} return NULL;
} //删除
Node *delFirst(Node *phead, int delData)
{
Node *p1=NULL, *p2=NULL; //此时需要双指针
p1 = phead; //保存头结点 while (p1 != NULL)
{
if (p1->data != delData)
{
p2 = p1; //p2保存的是p1的上一个位置
p1 = p1->pNext;
}
else
break;
} if (p1 != phead)
{
p2->pNext = p1->pNext; //跳过p1
free(p1); //删除p1
}
else
{
phead = phead->pNext;
free(p1); //头部删除
} return phead;
} //插入
Node *insertFirst(Node *phead, int insertData, int newData)
{
Node *p1 = NULL, *p2 = NULL; //此时需要双指针
p1 = phead; //保存头结点 while (p1 != NULL)
{
if (p1->data != insertData)
{
p2 = p1; //p2保存的是p1的上一个位置
p1 = p1->pNext; //向前移动
}
else
break;
} Node *pnew = malloc(sizeof(Node)); //构建新的节点
pnew->data = newData; //新节点赋值
pnew->pNext = NULL; if (phead == p1)
{
pnew->pNext = phead; //保存头结点
phead = pnew; //头部插入
}
else
{
pnew->pNext = p1;
p2->pNext = pnew; //插入
} return phead;
} //冒泡排序
void bubbleSort(Node *phead)
{
//数组可以随机访问任何一个元素,可以规避一些比较
//链表找到N个元素,必须先遍历N-1个元素
for (Node *p1 = phead; p1 != NULL; p1 = p1->pNext)
{
for (Node *p2 = phead; p2 != NULL; p2 = p2->pNext)
{
if (p1->data < p2->data)
{
int temp;
temp = p1->data;
p1->data = p2->data;
p2->data = temp;
}
}
}
} Node *fen(Node *pbegin, Node *pback)
{
int key = pbegin->data; //以第一个数据为分段 Node *p = pbegin; //第一个节点
Node *q = pbegin->pNext; //第二个节点 while (q != pback)
{
if (q->data < key)
{
p = p->pNext; //循环下一个节点 int temp = p->data; //交换
p->data = q->data;
q->data = temp;
}
q = q->pNext; //循环第二个指针 printf("\n枢轴为:(%d)", key);
printf("\n此时数:");
ShowAll(pbegin); } int temp = p->data; //交换
p->data = pbegin->data;
pbegin->data = temp; printf("\n\n交换值:");
ShowAll(pbegin);
printf("\n-----------------------------------------------"); return p;
} //快速排序法:(双冒泡)
void quickSort(Node *pbegin,Node *pback)
{
if (pbegin != pback)
{
Node *pfen = fen(pbegin, pback); //取中间点,分成两段分别再进行快排 quickSort(pbegin, pfen); //前半段快排
quickSort(pfen->pNext, pback); //后半段快排
}
} //求链表节点个数(普通方法)
int getNum1(Node *phead)
{
int i = ;
for (; phead != NULL; phead = phead->pNext)
{
i++;
}
return i;
} //求链表节点个数(递归)
int getNum2(Node *phead)
{
if (phead == NULL)
return ;
else
return + getNum2(phead->pNext);
} //链表反转(普通方法)
Node *revList1(Node *phead)
{
if (phead == NULL || phead->pNext == NULL)
return phead;
else
{
Node *pre = NULL;
Node *pcur = NULL;
Node *pnext = NULL; pre = phead;
pcur = phead->pNext;
while (pcur != NULL)
{
pnext = pcur->pNext; //备份下一个节点
pcur->pNext = pre; //第一个节点指向NULL,此时pre指向NULL(指针反转) pre = pcur; //前进
pcur = pnext; //轮替前进
} phead->pNext = NULL; //注意尾节点置空
phead = pre;
} return phead;
} //链表反转(递归方法)
Node *revList2(Node *phead)
{
if (phead == NULL || phead->pNext == NULL)
return phead;
else
{
Node *pnext = phead->pNext; //顺序 Node *Head = revList2(pnext); //轮询所有的节点,递归调用 pnext->pNext = phead; phead->pNext = NULL; //逆序 return Head;
}
} //链表合并
Node *mergeList(Node *phead3, Node *phead1, Node *phead2)
{
Node *pcur1 = phead1;
Node *pcur2 = phead2; while (pcur1 != NULL || pcur2 != NULL)
{
if (pcur1 != NULL && pcur2 != NULL)
{
if (pcur1->data < pcur2->data)
{
phead3 = addBack(phead3, pcur1->data);
pcur1 = pcur1->pNext;
}
else
{
phead3 = addBack(phead3, pcur2->data);
pcur2 = pcur2->pNext;
}
}
else
{
while (pcur1 != NULL)
{
phead3 = addBack(phead3, pcur1->data);
pcur1 = pcur1->pNext;
}
while (pcur2 != NULL)
{
phead3 = addBack(phead3, pcur2->data);
pcur2 = pcur2->pNext;
} break;
}
} return phead3;
} //获取链表的中间节点
Node *getMid(Node *phead)
{
if (phead == NULL || phead->pNext == NULL)
return phead;
else
{
Node *p1 = phead; //一次前进一步
Node *p2 = phead; //一次前进两步 while (p2->pNext != NULL) //注意循环条件,而不是p2 != NULL
{
p1 = p1->pNext;
p2 = p2->pNext;
if (p2->pNext != NULL)
p2 = p2->pNext;
} return p1;
}
} //判断链表是否有环
int judgeCircle(Node *phead)
{
int flag = ;
for (Node *p1 = phead, *p2 = phead; p1 != NULL && p2 != NULL; p1 = p1->pNext, p2 = p2->pNext) //死循环
{
if(p2->pNext!=NULL) //p2一次前进两步,而p1一次前进一步
p2 = p2->pNext; if (p1 == p2)
{
flag == ; //p1追上了p2,有环
break;
} } return flag;
}

main.c :

 #include "LinkList.h"

 void main()
{
Node *phead = NULL;
//init(phead); //初始化,头结点不分配内存,这里不能初始化头结点 phead = addBack(phead, ); //尾插
phead = addBack(phead, );
phead = addBack(phead, );
phead = addBack(phead, );
phead = addBack(phead, );
phead = addBack(phead, ); //addHead(&phead, 9); //头插
//addHead(&phead, 22);
//addHead(&phead, 41);
//addHead(&phead, 18);
//ShowAll(phead); //Node *pfind = searchFirst(phead, 13);
//pfind->data = 33;
//ShowAll(phead); //Node *pchange = changeFirst(phead, 14,93);
//ShowAll(phead); //ShowAll(phead);
//printf("\n\n");
//phead = delFirst(phead, 24);
//ShowAll(phead); //printf("\n\n");
//insertFirst(phead, 11, 100);
//ShowAll(phead); printf("排序前:");
ShowAll(phead);
printf("\n\n"); //bubbleSort(phead);
quickSort(phead, NULL); printf("\n\n");
printf("排序后:");
ShowAll(phead);
printf("\n"); printf("%d\n", getNum2(phead)); phead = revList1(phead);
ShowAll(phead);
printf("\n");
phead = revList2(phead);
ShowAll(phead);
printf("\n"); Node *phead1 = NULL;
phead1 = addBack(phead1, );
phead1 = addBack(phead1, );
phead1 = addBack(phead1, );
phead1 = addBack(phead1, );
phead1 = addBack(phead1, ); Node *phead2 = NULL;
phead2 = addBack(phead2, );
phead2 = addBack(phead2, );
phead2 = addBack(phead2, );
phead2 = addBack(phead2, ); printf("\n\n\n");
ShowAll(phead1);
printf("\n");
ShowAll(phead2);
printf("\n"); Node *phead3 = NULL;
phead3 = mergeList(phead3, phead1, phead2);
ShowAll(phead3);
printf("\n"); Node *pmid = getMid(phead3);
printf("%d\n", pmid->data); Node *phead4 = NULL;
phead4 = addBack(phead4, );
phead4 = addBack(phead4, );
phead4 = addBack(phead4, );
phead4 = addBack(phead4, );
phead4 = addBack(phead4, );
phead4 = addBack(phead4, );
phead4 = addBack(phead4, ); Node *p = phead4;
for (; p->pNext != NULL; p = p->pNext)
{
}
p->pNext = phead4; ShowCircleLink(phead4); //打印环形链表
printf("\n");
printf("%d\n", judgeCircle(phead4)); system("pause");
}

C语言实现单链表,并完成链表常用API函数的更多相关文章

  1. C语言实现单链表-03版

    在C语言实现单链表-02版中我们只是简单的更新一下链表的组织方式: 它没有更多的更新功能,因此我们这个版本将要完成如下功能: Problem 1,搜索相关节点: 2,前插节点: 3,后追加节点: 4, ...

  2. C语言实现单链表-02版

    我们在C语言实现单链表-01版中实现的链表非常简单: 但是它对于理解单链表是非常有帮助的,至少我就是这样认为的: 简单的不能再简单的东西没那么实用,所以我们接下来要大规模的修改啦: Problem 1 ...

  3. 「C语言」单链表/双向链表的建立/遍历/插入/删除

    最近临近期末的C语言课程设计比平时练习作业一下难了不止一个档次,第一次接触到了C语言的框架开发,了解了View(界面层).Service(业务逻辑层).Persistence(持久化层)的分离和耦合, ...

  4. C语言实现单链表节点的删除(带头结点)

    我在之前一篇博客<C语言实现单链表节点的删除(不带头结点)>中具体实现了怎样在一个不带头结点的单链表的删除一个节点,在这一篇博客中我改成了带头结点的单链表.代码演示样例上传至 https: ...

  5. C/C++语言实现单链表(带头结点)

    彻底理解链表中为何使用二级指针或者一级指针的引用 数据结构之链表-链表实现及常用操作(C++篇) C语言实现单链表,主要功能为空链表创建,链表初始化(头插法),链表元素读取,按位置插入,(有序链表)按 ...

  6. 单链表的插入伪算法和用C语言创建单链表,并遍历

    非循环单链表插入结点伪算法讲解 q插入p之后的伪算法:第一种表示方法:r = p->pNext; // p->pNext表示的是所指向结点的指针域,指针域又是指向下一个结点的地址p-> ...

  7. C语言一个单链表的实现

    -- 所谓链表记住一句即可:地址不连续,大家只是握个手而已: list0.c #include<stdio.h> #include<malloc.h> typedef int ...

  8. 数据结构图文解析之:数组、单链表、双链表介绍及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  9. JAVA 链表操作:单链表和双链表

    主要讲述几点: 一.链表的简介 二.链表实现原理和必要性 三.单链表示例 四.双链表示例 一.链表的简介 链表是一种比较常用的数据结构,链表虽然保存比较复杂,但是在查询时候比较便捷,在多种计算机语言都 ...

随机推荐

  1. synchronized的简单理解

    synchronized能够保证在同一时刻只有一个线程执行该段代码. 使用synchronized能够防止多个线程同时并发访问程序的某些资源. synchronized既可以修饰变量,也可以修饰方法, ...

  2. 127. Word Ladder (Tree, Queue; WFS)

    Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest t ...

  3. bootstrop-datatime参数配置

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  4. Django基础学习七之如何配置django+mysql

    很久没有更新博客了,也有段时间没有持续性的学习了,感觉堕落了,今天继续开始学习吧 今天主要来学习一下在django下配置mysql的数据库和使用admin用户管理数据库 1.在project中的set ...

  5. 3-java_string学习笔记:

    java中String的常用方法

  6. PHP半年了,已经可以独立支撑项目,几点心得记录

    从去年12开始零基础学习PHP,到现在可以独立支撑项目,感谢PHP的强大,成熟.入门容易,记录几点心得: 1.思维比什么都重要,方法要靠实践证明: 2.多写.多试,不要怕遇到坑,每一个坑都是你前进路上 ...

  7. Laravel 使用 seeder 使用要点

    一.关于 DB use DB; 再使用 DB::table(database.table)->get(); 二.关于 ERROR 1366 (HY000): Incorrect string v ...

  8. Java中二叉排序树

    package com.ietree.basic.datastructure.tree; import java.util.ArrayDeque; import java.util.ArrayList ...

  9. Android布局属性说明

    Android布局LinearLayout注意设置属性android:orientation属性,否则有的组件可能无法显示. 该属性不设置时默认为horizontal.此时第一个控件的宽度若设置成“f ...

  10. IRC聊天指南

    参考https://www.cnblogs.com/fzzl/archive/2011/12/26/2302637.html