1.前言
上一期我们讲到了简单链表的实现,但是,简单链表不能满足我们在实际场景的各种运用,例如,对链表的删除,在指定区域插入信息或删除,学好链表既可以为我们接下来实现贪吃蛇打好基础
2.实现删除(前删与尾删)
前提 这是SLNode内部
typedef struct SListnode {
int data;
struct SListnode* next;
}SLNode;
1.尾删
在进行代码的实现前,我们需要整理思路,画图便是最优解
我们这样给头文件给定一个删除接口
void SLPopBack(SLNode** pphead);
思路:
总的一个思路是这样,我们需要遍历整个链表,如果遍历到最后一个节点的下一个节点为空,那么便可以知道他就是链表的最后一个,接着就可以把他释放掉,便完成了链表尾节点的删除,原理很简单,实现起来却有不少需要注意的地方,可不敢忽略了。
开始代码的实现:
在第一步,就有坑等着你,在进行遍历之前,我们是不是应该进行对传过来的pphead进行断言,来判断它为真,接着,我们要判断pphead是不是已经是链表的最后一个了(也就是说整个链表只有他一个数据(可怜)),如果是最后一个数据,那么我们直接释放赋空就好了,代码如下:
assert(pphead);
assert(*pphead);
if ((*pphead)->next == NULL) {
free(*pphead);
pphead = NULL;
}
接下来,也就是该正式处理尾删的操作了,在开始时,我们给一个头指针用来遍历链表,再给一个prev指针指向空。
SLNode* prev = NULL;
SLNode* ptail = *pphead;
接下来,进行链表的遍历找到链表的最后一个节点,这里我们可以用while循环来遍历,而while循环条件我们可以这样写
while(ptail->next!=NULL){
prev=ptail;
ptail=ptail->next;
}
在遍历到最后一个后,我们也要把prev和ptail的指向修改一下,也就是当前的prev还是指向要删除的ptail,所以我们需要把prev的next指向ptail的next,然后就可以安心的把要删除的ptail free了。还有一件事!,别忘记了把当期的ptail赋为空。
完整代码:
void SLPopBack(SLNode** pphead)
{
assert(pphead);
assert(*pphead);
if ((*pphead)->next == NULL) {
free(*pphead);
pphead = NULL;
}
else {
SLNode* prev = NULL;
SLNode* ptail = *pphead;
while (ptail->next != NULL)
{
prev = ptail;
ptail = ptail->next;
}
prev->next = ptail->next;
free(ptail);
}
}
2.头删
接下来进行头删的操作,在正式进行删除前,我们还是一样的要进行断言来保证传参的有效性,
然后把头删除,将头指针的指向修改,同样的,我们还是进行画图说明
代码实现:首先,我们需要将链表的首节点设置为del,然后将首节点的位置指向修改为他的下一个节点,然后安心的free掉要删除的del节点,上代码!!!
SLNode* del = *pphead;
*pphead=(*pphead)->next;
free(del);
del = NULL;
同样的,别忘记把del赋值成del哦。
完整代码
void SLPopFront(SLNode** pphead) {
assert(pphead);
assert(*pphead);
SLNode* del = *pphead;
*pphead=(*pphead)->next;
free(del);
del = NULL;
}