书接上回
在其一中,我们讲解了单链表的设计、创建、以及尾插法,这回我们讲解链表的头插法,指定位置插入法,指定数据后面插入法
链表的头插法:
链表的头插法,即在头节点的后面、首元节点的前面插入节点(分不清头节点和首元节点的可以去百度搜一下)。通俗点说就像是插队一样。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void push_head(List* list, int data)
{
Node* newNode = createNode(data);
newNode->next = list->next;
list->next = newNode;
}
我们继续分步骤来为大家讲解:
- 和尾插法一样,push_head函数的参数,指定了我们要插入到哪个链表以及要插入什么数据
- 同样调用createNode创建需要插入的节点。
- 有人看到newNode->next = list->next 就懵逼了,前面介绍的时候说到,头插法是在头节点的后面、首元节点的前面插入节点,因此,newNode->next = list->next,代表了新的节点指向原来的首元节点,因为list->next其实就代表了首元节点了嘛。
- 而list->next = newNode,代表了头节点重定向 指向了新插入的节点。至此,头插法就完成了,如若依旧看不懂的话,建议手工画图,来模拟头插法的过程。
链表的指定位置插入法:
虽然链表并不像数组那样,存在索引,但是没有索引不妨碍我们抽象出一个索引出来
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void push_pos(List* list, int position, int data)
{
Node* curNode = list;
Node* newNode = createNode(data);
int location = 0; //用于抽象位置
while (curNode->next)
{
if (position == location++)
{
newNode->next = curNode->next;
curNode->next = newNode;
break;
}
curNode = curNode->next;
}
if (location == 0)
{
push_head(list, data);
}
if (position > location)
{
push_back(list, data);
}
}
但是由于指定位置插入法需要一些特殊情况,因此代码会复杂一些
需要考虑的情况有一下:
- 假如position为0,这个时候就相当于是头插了
- 链表并没有那么长,position参数给出的位置却比链表的节点数还要大
所以我们需要针对上述情况进行相应的调整。
我们依旧逐一解释:
- 我们先设置抽象出索引int location = 0来表示当前所在的位置(索引从0开始)
- 我们用while循环去遍历链表,curNode表示当前遍历到的节点
- 在循环体中,我们每次循环都进行 if 判断,如果position == location++,这里不仅起到了判断作用,而且先判断,再location自增,只要判断成立了,就用 if 中的代码进行插入操作,并且break退出循环
- if(location == 0),即为我们需要考虑的第一个情况:position的的值为0,那么这时候就相当于在 0 号位插入节点,所以我们果断调用先前写好的头插函数,就不用繁琐的复制粘贴了
- if(position > location),即为我们需要考虑的第二个情况:position参数比链表的节点数还要大。那么这个时候捏,我选择的解决方法就是直接用尾插,因此反正position的值没有意义,与其输出错误警告,不如直接在尾部插入节点。
在指定数据后面插入数据:
在指定数据后面插入数据也是比较简单的一种插法
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void push_after(List* list, int after, int data)
{
Node* newNode = createNode(data);
Node* curNode = list;
while (curNode->next)
{
if (curNode->data == after)
{
newNode->next = curNode->next;
curNode->next = newNode;
break;
}
curNode = curNode->next;
}
}
鉴于与之前的有雷同,所以长话短说。这里我们遍历整个链表,当if (curNode->data == after)满足条件时,代表我们找到了需要的数据,然后在插入后,break退出循环即可。
鉴于篇幅原因,链表的各种删法,会在其三当中进行讲解