文章转载请注明出处,加上原文地址链接,谢谢!https://blog.csdn.net/weixin_46959681/article/details/110672699
当前节点的判断
不论是在指定节点的后方或者前方插入新节点,我们第一步要做的是对当前节点做出判断,判断链表中的当前节点是否是我们所指定要插入新节点的节点。
如何在指定节点后方进行插入新节点?
以第三点节为指定节点,我们对指定节点、新节点以及节点之间的连接(主要通过指针实现)做出相应操作,具体有以下两个步骤:
- 以节点为对象元素,对彼此之间的函数对应关系做出修改(即修改指针的指向)。对应笔者所列的图片可以清楚的看到,第一步将链表中的第三节点和第四季节点的函数关系(即通过指针操作进行指向)赋值给新节点,让其指向第四个节点。笔者在此处用了比较数学化的说法,代码实现为
new->next = 3->next
。 - 第一步的基础之上,通过指针操作改变第三节点原来的指向,使第三节点和新节点之间建立指向关系。
代码实现为3.next = new
。
代码演示:
int insertFromBehind(struct Test *head, int data, struct Test *new)
{
//保持链表头部不动,使用指针point进行位移。
struct Test *point;
point = head;
//指针不指向野指针表明指针point指向链表当中的某一节点。
while(point != NULL)
{
if(point->data == data) //data为指定节点内的数据。
{
new->next = point->next;
point->next = new;
}
//该处的指针位移表示指针point访问到的数据与指定插入节点数不匹配,所以会位移继续匹配数据。
point = point->next;
}
}
如何在指定节点前方插入新节点?
对于在指定节点前方插入新节点的实现肯定与在后方插入完全不同。就在指定节点前方插入而言,可以分为两种不同的情形:
- 在链表头插入;(些许博文有使用到二级指针。)
- 在链表中某一个指定节点前方插入。
下面我们针对两种情况以画图的方式展开分析。
|在链表头部插入
在展开链表头部插入之前,我们必须有一个问题要解决。链表的第一个节点已经是链表头。在实现头部插入新节点时,势必会对链表头的地址进行相应的操作,这就要求我们必须创建一个含有地址变量的变量。此时的链表头 head 已经包含了第一个节点的地址为 一 级 指 针 \color{red}一级指针 一级指针 ,故此变量必须要包含链表头 head 这个一级指针的地址,即所谓 二 级 指 针 \color{red}二级指针 二级指针。笔者不打算使用二级指针,但是所用代码产生的效果是一样的。
图中的指针 head
和指针 point
都指向链表中第一个节点,head
用于固定链表头, point
用于指针的位移实现其他辅助操作,并且 point
永远指向当前节点。
如何实现链表头前方插入呢?思路大致如下:
- 检查当前节点的数据和头部节点的数据是否一致,即
point->data == data
; - 在数据匹配一致的基础上,将新节点的指针指向链表头, 即
new->next = head
。
片段代码演示:
struct Test *point;
point = head;
//判断当前节点的数据是否和链表头节点的数据匹配。
if(point->data == data)
{
//将新节点的指针指向链表头。
new->next = head;
//返回并使新节点成为头节点。
return new;
}
|在链表的其他指定节点前方插入
如何实现链表的其他节点前方插入新节点呢?大致思路如下:
- 保证指针在位移时永远非空,表明指针在链表的范围内进行活动,即
point->next != NULL
; - 判断当前节点的数据是否和指定节点的数据相匹配,即
if(point->next->data == data)
; - 在上一步成立的情况下,将新节点指向当前节点的下一个节点,即
new->next = point->next
。之后,将当前节点指向新节点,即point->next =new
。
代码演示:
//保证当前节点的下一个节点非空。
while(point->next != NULL)
{
//使用函数 printf() 追踪节点数据的流向非常重要!非常重要!
printf("data = %d, point = %d\n", point ->next->data, data);
//节点数据进行匹配。
if(point->next->data == data)
{
//新节点与下一个节点建立指向关联。
new->next = point->next;
point->next = new;
printf("insert success.\n");
return point;
}
point = point->next;
}
//超过链表范围,匹配数据失败。
printf("链表中没有节点包含这个数据 %d。\n", data);
return point;
提示:在演示代码敲完之后,整篇文章笔者从前往后仔细看了一遍,产生一个自己迷惑自己的乌龙。那就是指针 point 是指向当前节点,而形式参数 data 是指定的节点里的数据。两者千万不要混为一谈。🤣
两段代码合并放在一个窗口下
int insertFromBehind(struct Test *head, int data, struct Test *new)
{
struct Test *point;
//保持链表头部不动,使用指针point进行位移。
point = head;
//指针不指向野指针表明指针point指向链表当中的某一节点。
while(point != NULL)
{
//data为指定节点内的数据。
if(point->data == data)
{
new->next = point->next;
point->next = new;
}
//该处的指针位移表示指针point访问到的数据与指定插入节点数不匹配,所以会位移继续匹配数据。
point = point->next;
}
}
struct Test *insertFromfor(int insertFromBehind(struct Test *head, int data, struct Test *new))
{
struct Test *point;
point = head;
//判断当前节点的数据是否和链表头节点的数据匹配。
if(point->data == data)
{
//将新节点的指针指向链表头。
new->next = head;
//返回并使新节点成为头节点。
return new;
}
while(point->next != NULL)
{
//使用函数 printf() 追踪节点数据的流向非常重要。
printf("data = %d, point = %d\n", point ->next->data, data);
if(point->next->data == data)
{
//新节点与下一个节点建立指向关联。
new->next = point->next;
point->next = new;
printf("insert success.\n");
return point;
}
point = point->next;
}
//超过链表范围,匹配数据失败。
printf("链表中没有节点包含这个数据 %d。\n", data);
return point;
}
思索
在写文章的时候笔者渐渐有股莫名的感觉,就真实的项目代码而言肯定和笔者所敲的代码有些许差别。就以指定节点的形式参数而言,笔者不知道是不是直接以变量名 data
的形式传递,又或者用到了指针的方式。毕竟笔者只是初学者,企业里真实的项目根本没有实践过。
另外,关于主函数 main
的部分就不在多做演示了,合并添加下来展示,整片博文就过于庞大了。
文章更新记录
- 文章初步完成。「2020.12.5 21:47」
- 修改部分文字的表述。「2020.12.8 10:18」
- 一篇比较详细的C语言链表博文,没有用到二级指针。c语言链表详解(超详细)「2020.12.11 21:05」
- 修改了演示中错误的代码。 「2021.1.9 15:02」