c语言数据结构:单链表
Posted codeCJ的日常
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c语言数据结构:单链表相关的知识,希望对你有一定的参考价值。
各位朋友们,伙计们,大家好!
|
创建链表
链表链表,顾名思义,就是像链子一样连在一起的表,咳咳,虽说有些废话,但确实如此,它是结构体与结构体之间以指针互相连接着,上一个结构体的指针指向下一个结构体,这样就形成了一个链表,它相对于数组有什么好处呢,大家都知道,数组内的内存空间是预先分配好的,而且也不能在使用过程中动态的改变其空间大小,这样就会有一个很大的弊端,比如给一个int型数组分配了100个内存空间,那么它就只能最多存100个数据,超过了就完蛋,存少了还浪费内存,就很烦,然而链表就没有这个问题,你有多少数据就开辟多少内存空间,不要某个数据还可以释放掉其内存空间,而且支持多个不同类型的数据在一块,多好!所以,学会了链表,数组只能躲在一边默喊mmp。
咳咳,话不多说,上代码!
#include <stdio.h>
#include <stdlib.h> //此头文件包函malloc动态申请内存函数
//创建一个名为list的结构体
typedef struct list
{
//结构体数据,你想多整几个也行,我在这只放了一个,不是我想偷懒啊
int data;
//弄一个指向下一个结点的结构体的尾指针
struct list* next;
}L; //用typedef让L来代替struct list,节约点按键盘次数
//创建链表
//L* 为此函数的类型为L*也就是struct list*,返回结构体函数指针
L* creatorList()
{
//定义一个结构体指针并分配内存空间,分配大小为此结构体所占内存大小
L* headlist = (L*)malloc(sizeof(L));
//表头只是起到一个引导作用,所以不用给其赋值
//刚创建的链表为空,所以需要让表头的尾结点指向NULL
headlist->next = NULL;
//返回创建好的链表
return headlist;
}
创建结点
既然链表已经创建好了,那么接下来就是创建结点,结点里存放我们数据,结点的创建跟上面的操作类似,如果这块有啥问题可以直接来问我就可以了。
话不多说,上代码!
//创建结点
L* creatorNode(int data)
{
//跟之前创建链表的时候相同,结点也需要申请内存空间
L* newNode = (L*)malloc(sizeof(L));
//不过,之前创建的链表只有表头,只起到了引导作用
//所以,结点里面就可以放数据了
newNode->data = data;
//将结点的尾指针指向NULL
newNode->next = NULL;
//返回结点
return newNode;
}
插入结点
//函数参数为要插入的链表和要插入其中的结点
void insertNode(L* head,L* newNode)
{
//首先先让新结点的尾指针指向头结点的尾指针所指的结点
newNode->next = head->next;
//再让头结点的尾指针指向新结点
head->next = newNode;
}
void insertNode(L* head,L* newNode)
{
//首先再定义一个指针指向链表的头结点
L* pMove = head; //此做法是让head一直是链表头结点
while(pMove->next!=NULL) //判断pMove是否移动到了链表的最后一个结点
pMove = pMove->next; //使pMove移动至下一个节点
//循环完毕之后表示pMove已经指向了链表的最后一个结点
pMove->next = newNode; //将pMove,即最后的结点的尾指针指向新结点
}
void insertNode(L* head,L* newNode)
{
L* pMove = head; //此做法是让head一直是链表头结点
//判断pMove是否移动到了尾结点
while(pMove->next!=NULL)
{
//判断pMove所指结点所指结点的数据的数是否小于新结点的数据,然后再判
//断pMove所指结点的尾指针所指的结点的数据是否大于新结点数据
if(pMove->data<newNode->data&&pMove->next->data>newNode->data)
{
//条件成立,此下操作就跟头插法差不多
//让新结点的尾指针指向pMove所指结点的尾指针所指的结点
newNode->next = pMove->next;
//让pMove所指结点的尾指针指向新结点
pMove->next = newNode;
//插入完成,return返回
return;
}
//让pMove指向下一个结点
pMove = pMove->next;
}
//循环完毕后,此时pMove为链表尾结点,让pMove所指结点的尾指针指向新结点
pMove->next = newNode;
}
查询结点
大家用过数组吧,其实链表的查询方法就和数组差不多,比如我想在数组里找一个数据,我会用循环来让数组里的元素和我要查找的数一一比较,直到找到为止,而链表也是如此,不过只是将数组元素换成了链表结点。
上代码!!!
void queryNode(L* head,int data)
{
//定义一个整形i的目的是显示其所查询的数据在第几个结点
int i=1;
//这里我就不讲了,跟上面解释一样
L* pMove = head->next;
while(pMove)
{
//判断数据是否匹配
if(pMove->data==data)
{
//输出查找到的结点数据和它所在结点位置
printf("已找到数据:%d,它在第%d结点",pMove->data,i);
//已查找到,return返回,不让继续执行下面程序
return;
}
i++;
pMove = pMove->next;
}
//循环结束表示没有找到
printf("未找到匹配数据\n");
}
修改结点数据
上代码!!!
void changeNode(L* head,int data)
{
L* pMove = head->next;
while(pMove)
{
//如果数据匹配
if(pMove->data==data)
{
printf("请输入修改后的数据:");
scanf("%d",&data);
//将此结点数据修改
pMove->data = data;
printf("修改完成!\n");
return;
}
pMove = pMove->next;
}
//循环结束表示没有找到匹配结点
printf("未找到匹配结点\n");
}
删除结点
话不多说,上代码!!!
void deteleNode(L* head,int data)
{
L* pMove = head;
//定义一个结构体指针,指向pMove所指结点的下一个节点
L* dpMove = pMove->next;
while(dpMove)
{
//如果结点数据匹配
if(dpMove->data==data)
{
//这里的操作就跟头插入差不多
//让pMove所指结点的尾指针指向dpMove所指结点的尾指针所指的结点
pMove->next = dpMove->next;
//释放dpMove所指的结点内存
free(dpMove);
printf("删除完成!\n");
return;
}
pMove = pMove->next;
dpMove = pMove->next;
}
//循环结束表示没有找到匹配结点
printf("未找到匹配结点\n");
}
输出链表
终于到输出了,赶紧弄完去打把LOL,哈哈哈哈!
上代码!!!
void printlist(L* head)
{
//让PMove指向头结点的下一个结点
L* pMove = head->next;
//如果PMove所指结点为NULL,则表示其链表为空
if(pMove==NULL)
{
printf("链表为空\n");
return;
}
//这里的头是表示头结点,它起一个引导作用
printf("头");
//当pMove不为NULL,同不为0时
while(pMove)
{
//输出结点数据
printf("->%d",pMove->data);
//让pMove指向下一个结点
pMove = pMove->next;
}
//结点输出完输出NULL的意义为,能更直观的看到链表的结构
printf("->NULL\n");
}
销毁链表
话不多说了,上代码!!!
尾删法:
void detelelist(L* head)
{
L* pMove;
L* detele;
while(1)
{
pMove = head;
//如果下面的条件成立,表示链表为空,跳出循环
if(pMove->next==NULL)
break;
//判断pMove所指结点的尾指针所指的尾指针所指的结点是否为NULL
//此做法是为了给detele留个位位好释放它所指的尾结点
while(pMove->next->next!=NULL)
pMove = pMove->next;
//此时pMove所指的结点的尾指针所指的结点为尾结点
//让detele指向它!!!
detele = pMove->next;
//让pMove所指的结点的尾结点指向detele所指结点的尾指针所指,即NULL
pMove->next = detele->next;
//释放它!!!
free(detele);
//每释放一次输出一次链表
printlist(head);
}
//此时链表为空,将头结点指针置为NULL
head = NULL;
}
头删法:
void detelelist(L* head)
{
L* pMove = head->next;
while(pMove)
{
//让头结点的尾指针指向pMove所指结点的尾指针所指的结点
head->next = pMove->next;
//釈放する!!(释放它!!)
free(pMove);
//让pMove指向下一个结点
pMove = head->next;
//每释放一个结点输出一次链表
printlist(head);
}
//此时链表为空,将头结点指针置为NULL
head = NULL;
}
typedef struct list
{
int data;
struct list* next;
}L;
L* creatorList()
{
L* headlist = (L*)malloc(sizeof(L));
headlist->next = NULL;
return headlist;
}
L* creatorNode(int data)
{
L* newNode = (L*)malloc(sizeof(L));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
void insertNode(L* head,L* newNode)
{
L* pMove = head;
while(pMove->next!=NULL)
{
if(pMove->data<newNode->data&&pMove->next->data>newNode->data)
{
newNode->next = pMove->next;
pMove->next = newNode;
return;
}
pMove = pMove->next;
}
pMove->next = newNode;
}
void queryNode(L* head,int data)
{
int i=1;
L* pMove = head->next;
while(pMove)
{
if(pMove->data==data)
{
printf("已找到数据:%d,它在第%d结点",pMove->data,i);
return;
}
i++;
pMove = pMove->next;
}
printf("未找到匹配数据\n");
}
void changeNode(L* head,int data)
{
L* pMove = head->next;
while(pMove)
{
if(pMove->data==data)
{
printf("请输入修改后的数据:");
scanf("%d",&data);
pMove->data = data;
printf("修改完成!\n");
return;
}
pMove = pMove->next;
}
printf("未找到匹配结点\n");
}
void deteleNode(L* head,int data)
{
L* pMove = head;
L* dpMove = pMove->next;
while(dpMove)
{
if(dpMove->data==data)
{
pMove->next = dpMove->next;
free(dpMove);
printf("删除完成!\n");
return;
}
pMove = pMove->next;
dpMove = pMove->next;
}
printf("未找到匹配结点\n");
}
void printlist(L* head)
{
L* pMove = head->next;
if(pMove==NULL)
{
printf("链表无数据\n");
return;
}
printf("头");
while(pMove)
{
printf("->%d",pMove->data);
pMove = pMove->next;
}
printf("->尾\n");
}
void detelelist(L* head)
{
L* pMove = head->next;
while(pMove)
{
head->next = pMove->next;
free(pMove);
pMove = head->next;
printlist(head);
}
head = NULL;
}
void main()
{
L* list = creatorList();
L* newNode;
int data;
while(1)
{
printf("请输入结点数据(0为停止输入):");
scanf("%d",&data);
if(data==0)
break;
newNode = creatorNode(data);
insertNode(list,newNode);
printf("输出链表:\n");
printlist(list);
printf("\n");
}
printf("请输入所要查找的数据:");
scanf("%d",&data);
queryNode(list,data);
printf("\n请输入所要修改的结点数据:");
scanf("%d",&data);
changeNode(list,data);
printlist(list);
printf("\n请输入所要删除的结点:");
scanf("%d",&data);
deteleNode(list,data);
printlist(list);
getchar();getchar();
printf("\n删除链表数据:\n");
detelelist(list);
}
代码里插入结点函数我用了排序插入法,销毁链表函数我用了头删法,大家可以使用上面的其他方法,如果有什么问题可以问我,下次我将做一个双向链表,ok,希望大家看完之后能点一个在看、分享,作者在此多谢啦!!!
至此,所有单链表操作完结!!撒花!! |
以上是关于c语言数据结构:单链表的主要内容,如果未能解决你的问题,请参考以下文章
C/C++语言数据结构快速入门(代码解析+内容解析)链表(单链表,双链表,循环链表,静态链表)
C/C++语言数据结构快速入门(代码解析+内容解析)链表(单链表,双链表,循环链表,静态链表)