继续书接上回
在其二当中我们讲解了链表的头插法,任意插法,指定数据后面插法,那么最后一节,我们讲解链表的头删法,尾删法,以及指定位置删法
头删法:
顾名思义,就是把排第一的那个节点删掉。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void pop_head(List* list)
{
Node* tempNode = list->next;
if (tempNode == NULL)
{
return;
}
list->next = tempNode->next;
free(tempNode);
}
逐一讲解:
- 首先我们创建了一个tempNode,代表的是首元节点,如果首元节点为NULL,那么就不需要再删除掉了,直接return
- 若首元节点不为空,我们就把 头节点 指向 首元节点的下一个节点,那么tempNode->next这个节点就成了新的首元节点啦
- 最后我们还要调用free函数释放掉原来的首元节点,避免内存泄漏
尾删法:
尾删法即把最后的节点删除掉,就像一辆火车把最后的那节车厢给脱钩一样。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void pop_back(List* list)
{
Node* backNode = list->next;
if (!backNode)
{
return;
}
while (backNode->next != NULL)
{
backNode = backNode->next;
}
Node* preNode = list;
while (preNode->next != backNode)
{
preNode = preNode->next;
}
preNode->next = NULL;
free(backNode);
}
这里的尾删法最重要的一个问题便是,怎么找到尾节点?以及要把倒数第二个节点重新指向为NULL
逐一讲解:
- Node* backNode = list->next 这个代码,是为了从首元节点开始遍历,并且下面进行了 if 的判断,是为了避免链表本来就只有一个头节点,实现不了尾删
- 然后我们使用while循环,来找到尾节点,backNode即代表尾节点的意思
- 重点来了,我们又定义了一个preNode,这个代表的是尾节点的前一个节点,因为我们需要让倒数第二个节点指向为NULL嘛
- 第二个while循环的条件为 preNode->next != backNode,即只要preNode的指向不是尾节点,就一直向下找,当循环结束后,preNode即为倒数第二个节点
- preNode->next = NULL 让倒数第二个节点重新指向空,然后用free函数释放掉原来的尾节点,这样原来的尾节点就被成功删除,而preNode就成了新的尾节点
指定位置删法:
和之前讲到的指定位置插入一样的原理,但是指定位置删除则需要考虑更多的情况。
需要考虑的情况如下:
- 要删除的位置刚好为首元节点,即指定的位置为0
- 要删除的位置是中间节点
- 要删除的位置刚好为尾节点
- 指定的位置,比链表的节点数量要大
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void pop_pos(List* list, int position)
{
Node* curNode = list;
int location = 0;
if (position == 0)
{
pop_head(list);
return;
}
while (curNode)
{
if (position == location++)
{
if (curNode->next == NULL)
{
pop_back(list);
return;
}
else
{
Node* popNode = curNode->next;
Node* backNode = popNode->next;
curNode->next = backNode;
free(popNode);
return;
}
}
curNode = curNode->next;
}
if (position > location)
{
pop_back(list);
}
}
逐一讲解:
- 我们通过int location = 0 抽象出一个链表的索引
- 紧接着,我们判断传入的position的值是否为0,是就直接调用前面写好的pop_head函数,然后返回即可
- 然后我们就要考虑另外两种情况,我们用while循环遍历整个链表,循环里面放一个if 判断是否到达了指定的位置
- 如果到达了位置,我们再用if (curNode->next == NULL) 来判断指定位置的节点是否为尾节点,是的话,我们直接调用写好的pop_back函数即可
- 如果不是,即代表了要删除的节点在中间的位置,Node* popNode = curNode->next,popNode代表了我们要删除的节点,这个节点为curNode->next。紧接着的Node* backNode = popNode->next; curNode->next = backNode; 是把断开的节点连接起来的,如果看不懂建议可以手工画图理解
- 最后我们释放掉popNode即可