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. Android中asset文件夹与raw文件夹的区别深入解析(转)

    *res/raw和assets的相同点:1.两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制.*res/raw和assets的不同点:1.res/raw中的文件会被映射到R.j ...

  2. ajax传递数组及后台接收

    ajax传递的是{"items":arr},其中arr=[]; 在后台String[] items=req.getParameterValues("items" ...

  3. Jenkins修改端口号(成功率高)

    转载:http://blog.csdn.net/dzh0622/article/details/52470634 Jenkins默认的端口号是8080,修改方法: 1. 打开终端,cd 到Jenkin ...

  4. Halcon中xld的常见特征的含义总结

    如下图:

  5. 简述json模块

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写,他的数据结构与Python中的字典一样,键值对来表示数据间的关系,可以包含列表. 在编写 ...

  6. sublime填坑之旅: 格式代码, 缩进缩进

    前言:sublime是一款编程神器,轻巧又强大,适用于各种语言.这里介绍下如何快速缩进混乱代码,方便代码阅读. 原料:sublime text 3 1 混乱代码如下: 2  格式菜单选择: 英文: 菜 ...

  7. Opencascade、OpenGL和OpenSceneGraph的区别与联系

    OpenGL只是三维显示 Openscenegraph基于场景图的概念,它提供一个在OpenGL之上的面向对象的框架,从而能把开发者从实现和优化底层图形的调用中解脱出来 Opencascade更适合算 ...

  8. ZOJ3696 Alien's Organ 2017-04-06 23:16 51人阅读 评论(0) 收藏

    Alien's Organ Time Limit: 2 Seconds      Memory Limit: 65536 KB There's an alien whose name is Marja ...

  9. java中null转换成其它类型

    对null进行强转会不会抛错.测试结果是,如果把null强转给对象,是不会抛异常的,因为本身对象是可以为null的.但是如果是基本类型,比如 int i = (Integer)obj的强转,其实内部会 ...

  10. 转:css实现强制不换行/自动换行/强制换行

    css实现强制不换行/自动换行/强制换行 [日期:2007-08-22] 来源:  作者: [字体:大 中 小] 强制不换行 div{ white-space:nowrap;} 自动换行 div{  ...