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. [leetcode]273. Integer to English Words 整数转英文单词

    Convert a non-negative integer to its english words representation. Given input is guaranteed to be ...

  2. 1-为什么java的main方法必须是静态的

    为什么java的main方法必须是静态的   今天看类型信息时发现一个问题,不能再main方法中打印this关键字的信息,这时想起了之前的知识,不能再静态方法中调用this.理由很简单,this表示“ ...

  3. Gcc And MakeFile Level1

    简单介绍gcc And make 的使用 基本编译 gcc a.c b.c -o exeName 分步编译 gcc -c a.c -o a.o gcc a.o b.c -o main.o 使用Make ...

  4. Sprint boot notes

    1. spring.io 官网 2. http://javainuse.com/spring/sprboot spring boot学习资源 3. spring boot websocketss视频  ...

  5. __slots__(面向对象进阶)

    1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性) 2.引子:使用点来访问属性本质就是在访问类或者对象的__dic ...

  6. docker+zookeeper+mesos+marathon集群

    实验环境: 主机名 ip地址 运行服务 安装组件 docker-master1 192.168.20.210 zookeepermesos-mastermarathon mesosmarathonme ...

  7. centos环境下登录mysql报 ERROR 1045 (28000)怎么解决

    centos环境下登录mysql报 ERROR 1045 (28000)怎么解决 新入手一台虚拟机,Centos7系列的操作系统,安装mysql后,执行连接出现了Mysql ERROR 1045 (2 ...

  8. .net二纬码标签打印

    在企业开发中经常用到二纬码标签,本文详细介绍.net环境下整个二纬码解决方案. 开发环境  vs2008  DevExpress8.3  ThoughtWorks.QRCode (二纬码生成组件,高版 ...

  9. POJ 1739 Tony's Tour (DP)

    题意:从左下角到右下角有多少种走法. 析:特殊处理左下角和右下角即可. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000 ...

  10. [label][git-commands] Several Git Commands

    The process of Git commands Operation 1. git commit -m 'fist post' Windows PowerShellCopyright (C) 2 ...