目录
1.尾删函数SLTPopBack
代码示例(写入SList.c)
在SList.h中写入该函数的声明
main.c部分代码改为
编辑
分析
解决方法
方法1:双指针算法(快指针tail,慢指针pretail)
方法2
2.头删函数SLTPopFront
一个节点示意图
多个节点示意图
代码示例(写入SList.c)
在SList.h中写入该函数的声明
main.c部分代码改为
承接87.【C语言】数据结构之链表的头插和尾插文章
1.尾删函数SLTPopBack
代码示例(写入SList.c)
void SLTPopBack(SLTNode** pphead)
{SLTNode* tail = *pphead;while (tail->next != NULL){tail = tail->next;}free(tail);tail = NULL;
}
在SList.h中写入该函数的声明
main.c部分代码改为
void TestSList1()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPopBack(&plist);SLTPrint(plist);
}
运行后出了问题
分析
虽然为tail使用free函数并将tail置NULL,但是tail前面的节点含的指针并没有置NULL,导致其为野指针,因而出现了-572662307这样的随机值
解决方法
找到tail前的节点含的指针,并将其置NULL
方法1:双指针算法(快指针tail,慢指针pretail)
void SLTPopBack(SLTNode** pphead)
{SLTNode* pretail = NULL;//初始化慢指针SLTNode* tail = *pphead;while (tail->next != NULL){ pretail = tail;//待tail指针内容改变前,先赋值给慢指针tail = tail->next;}pretail->next = NULL;//tail的前一个节点含的指针置NULLfree(tail);tail = NULL;
}
方法2
void SLTPopBack(SLTNode** pphead)
{SLTNode* tail = *pphead;while (tail->next->next != NULL){ tail = tail->next;}free(tail->next);tail->next = NULL;
}
tail->next->next != NULL//跨了一个节点
看起来没有问题,但是将main.c部分代码改成
void TestSList1()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPopBack(&plist);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);SLTPopBack(&plist);SLTPrint(plist);
}
就会出问题
当链表为1->NULL时,tail->next->next != NULL会导致读取访问权限冲突(原因:tail->next为NULL,NULL->next不合法)
如果用方法1,也会出现同样的问题
因此要在尾删函数的一开始做出判断:1.是否为空链表? 2.链表是否只有一个节点?
修正后的代码
void SLTPopBack(SLTNode** pphead)
{assert(pphead);assert(*pphead);//检查是否为空链表,空链表不可以尾删//检查链表是否只有一个节点if ((*pphead)->next == NULL){free(*pphead);//*pphead就是plist*pphead = NULL;}else{SLTNode* tail = *pphead;while (tail->next->next != NULL){tail = tail->next;}free(tail->next);tail->next = NULL;}
}
注意断言的顺序:先断言pphead,再断言*pphead!
2.头删函数SLTPopFront
和尾删函数一样:一开始做出判断:1.是否为空链表? 2.链表是否只有一个节点?
空链表不可头删,直接断言
一个节点示意图
多个节点示意图
一个节点和多个节点的处理方式可以合并在一起
代码示例(写入SList.c)
void SLTPopFront(SLTNode** pphead)
{assert(pphead);assert(*pphead);//检查是否为空链表SLTNode* first = *pphead;*pphead = first->next;first = NULL;
}
注意断言的顺序:先断言pphead,再断言*pphead!
在SList.h中写入该函数的声明
main.c部分代码改为
void TestSList1()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);SLTPopFront(&plist);SLTPrint(plist);
}