简介
动态链表的具体实现是有些抽象的,所以想学好需要结合图示,把实现的逻辑想明白,才能快速上手。
实现原理
指针
指针是c语言很基础的一个知识点,这里不多赘述,理解了指针才能理解链表
B站一个讲C语言的系列视频,我学到的动态链表也是来自这个系列
链表
节点
一个节点有若干数据,和一个指向下一个节点的指针
typedef struct//定义链表结点结构体类型
{
int data;
struct node *next;
}NODE;//定义类型别名
链表
空白的格子是数据,如上节点案例,只有一个int类型的变量
所以这里一个节点只有一个int类型的数据
第二个格子则是指向下一个节点的指针
一个节点存储着数据的同时,有一个指向下一个节点的指针
像图中那样,将每一个节点的指针(称为末节点)串起来,就形成了静态链表(无法增删节点)
动态链表
在静态链表的基础上,能增加和删除节点的
就是动态链表
增加节点
有如下面这个链表
原本第二个节点指向第三个节点
现在将第二个节点指向新加入的储存的int变量=6的新节点
然后将新节点指向原本的第三个节点
随后新节点变成第三个节点
原本的第三个节点变成第四个节点
整个链表就连起来,增加了节点
删除节点
有如下面这个链表
原本第一个节点的next指向第二个节点
现在将第一个节点的next指向第三个节点
然后将第二个节点内存释放(相当于删掉)
随后链表里就剩下三个节点
整个链表依旧连起来,且删掉了目标节点
代码解析
库函数
#include<stdio.h>
#include<stdlib.h>
定义节点结构体
一个节点有多少个数据都可以定义
示例里只定义了一个int变量
最后定义指向下一个节点的末节点
typedef struct//定义链表结点结构体类型
{
int data;
struct node *next;
}NODE;//定义类型别名
创建并遍历链表
malloc()是一个分配内存的函数
sizeof(NODE)表示申请的这个节点的大小
在循环中,将新节点的数据录入,并指向下一个节点,直到负数结束循环,将最后一个节点指向空,即NULL,形成一个链表
然后写一个函数遍历链表,输出链表的每一个节点的存储的值
/*
函数:创建动态链表
输入:链表数值,直到 负数
输出: 无
*/
NODE *create()
{
NODE *head,*now,*q;//now指向当前节点,q指向下一个结点
int t;//用于暂存输入的成绩
head=(NODE*)malloc(sizeof(NODE)); //创建头节点
now=head;//指向头节点
while(1)
{
printf("请输入一个整数成绩(以负数结束):");
scanf("%d",&t);
if(t<0) break;
q=malloc(sizeof(NODE));//q指向新结点
q->data=t; //将t的值赋予新节点指向的数据域
now->next=q; //将新结点连接到链表中
now=q;
}
now->next=NULL;//末结点指向空
return head;//返回头结点
}
/*
函数:遍历链表
输入:链表节点
输出:链表每个节点储存的值
*/
void print(NODE *head)
{
NODE *now;//当前节点
now=head->next;
if(now==NULL)
printf("该链表为空!\n");
else
{
printf("链表中的数据为:");
while(now!=NULL)
{
printf("->%d",now->data);
now=now->next;
}
}
printf("\n");
return;
}
效果如图
增加节点
先通过输入一个值确定要增加的节点在链表中位置,来实现定位,姑且将新节点的上一个节点称为前节点
完成定位后,增加一个新节点,然后将前节点指向新节点,将新节点指向前节点原来指向的下一个节点,从而连接起来成为新链表,这里不太理解的可以往回看集合图示更好理解
/*
函数:增加链表的节点
输入:链表头节点
输出:无
*/
void add(NODE *head)
{
int Target,NewTarget;//暂存两个数值
printf("请输入增加的节点的上一节点的值:");
scanf("%d",&Target);
printf("请输入新节点的值:");
scanf("%d",&NewTarget);
NODE *Now,*NewNode,*Nextp;//分别表示当前节点,新节点,下一节点
Now=head;
Nextp=Now->next;//指向下一节点
NewNode=malloc(sizeof(NODE));//申请一个NODE大小的空间给新节点
NewNode->data=NewTarget;//将值赋给新节点
while(1)
{
Nextp=Now->next;//将Nextp指向下一节点
if(Now->data==Target)//如果当前节点的值等于目标值
{
Now->next=NewNode;//将当前节点指向新节点
NewNode->next=Nextp;//将新节点指向下一节点完成链表连接
printf("节点增加成功\n");//成功反馈
break;//退出循环以结束函数
}
else if(Now->next==NULL)
{
printf("节点增加失败,未查找到上一节点的值\n");//失败反馈
break;//退出循环以结束函数
}
else Now=Now->next;//遍历下一节点来寻找要删除的值
}
return;
}
删除节点
删除节点就很好理解了,输入要删除的节点的值,然后遍历链表寻找这个值,找到之后,将被删节点的前节点,指向被删节点的后节点,这样被删节点就被孤立出来了,然后释放内存,成功将这个节点删除
/*
函数:删除链表的节点
输入:链表头节点,删除的节点
输出:无
*/
void dele(NODE *head)
{
NODE *now,*nextp;
int Target;
printf("请输入要删除的值:");
scanf("%d",&Target);
now=head;
nextp=now->next;
while(1)
{
if(nextp->data==Target)
{
now->next=nextp->next;
free(nextp);
printf("节点删除成功\n");
break;
}
else
{ now=nextp;
nextp=nextp->next;
}
if(nextp->next==NULL)
{
printf("节点删除失败,未查找到要删除的值\n");
break;
}
}
return;
}
主函数
看注释即可,不多赘述
int main()
{
NODE *h; //定义一个节点类型的指针
h=create();//创建一个链表并返回头指针给h,将h设为头指针
print(h); //遍历链表检查是否成功创建
dele(h); //删除一个节点
print(h); //遍历链表检查是否成功删除
add(h); //增加一个节点
print(h); //遍历链表检查是否成功增加
return 0;
}
完整代码
#include<stdio.h>
#include<stdlib.h>
typedef struct//定义链表结点结构体类型
{
int data;
struct node *next;
}NODE;//定义类型别名
/*
函数:创建动态链表
输入:链表数值,直到 负数
输出: 无
*/
NODE *create()
{
NODE *head,*now,*q;//now指向当前节点,q指向下一个结点
int t;//用于暂存输入的成绩
head=(NODE*)malloc(sizeof(NODE)); //创建头节点
now=head;//指向头节点
while(1)
{
printf("请输入一个整数成绩(以负数结束):");
scanf("%d",&t);
if(t<0) break;
q=malloc(sizeof(NODE));//q指向新结点
q->data=t; //将t的值赋予新节点指向的数据域
now->next=q; //将新结点连接到链表中
now=q;
}
now->next=NULL;//末结点指向空
return head;//返回头结点
}
/*
函数:遍历链表
输入:链表节点
输出:链表每个节点储存的值
*/
void print(NODE *head)
{
NODE *now;//当前节点
now=head->next;
if(now==NULL)
printf("该链表为空!\n");
else
{
printf("链表中的数据为:");
while(now!=NULL)
{
printf("->%d",now->data);
now=now->next;
}
}
printf("\n");
return;
}
/*
函数:增加链表的节点
输入:链表头节点
输出:无
*/
void add(NODE *head)
{
int Target,NewTarget;//暂存两个数值
printf("请输入增加的节点的上一节点的值:");
scanf("%d",&Target);
printf("请输入新节点的值:");
scanf("%d",&NewTarget);
NODE *Now,*NewNode,*Nextp;//分别表示当前节点,新节点,下一节点
Now=head;
Nextp=Now->next;//指向下一节点
NewNode=malloc(sizeof(NODE));//申请一个NODE大小的空间给新节点
NewNode->data=NewTarget;//将值赋给新节点
while(1)
{
Nextp=Now->next;//将Nextp指向下一节点
if(Now->data==Target)//如果当前节点的值等于目标值
{
Now->next=NewNode;//将当前节点指向新节点
NewNode->next=Nextp;//将新节点指向下一节点完成链表连接
printf("节点增加成功\n");//成功反馈
break;//退出循环以结束函数
}
else if(Now->next==NULL)
{
printf("节点增加失败,未查找到上一节点的值\n");//失败反馈
break;//退出循环以结束函数
}
else Now=Now->next;//遍历下一节点来寻找要删除的值
}
return;
}
/*
函数:删除链表的节点
输入:链表头节点,删除的节点
输出:无
*/
void dele(NODE *head)
{
NODE *now,*nextp;
int Target;
printf("请输入要删除的值:");
scanf("%d",&Target);
now=head;
nextp=now->next;
while(1)
{
if(nextp->data==Target)
{
now->next=nextp->next;
free(nextp);
printf("节点删除成功\n");
break;
}
else
{ now=nextp;
nextp=nextp->next;
}
if(nextp->next==NULL)
{
printf("节点删除失败,未查找到要删除的值\n");
break;
}
}
return;
}
int main()
{
NODE *h;
h=create();//创建一个链表并返回头指针给h,将h设为头指针
print(h);
dele(h);
print(h);
return 0;
}