91.【C语言】数据结构之单向链表的头删和尾删

目录

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)

cpp 复制代码
void SLTPopBack(SLTNode** pphead)
{
	SLTNode* tail = *pphead;
	while (tail->next != NULL)
	{
		tail = tail->next;
	}
	free(tail);
	tail = NULL;
}

在SList.h中写入该函数的声明

main.c部分代码改为

cpp 复制代码
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)

cpp 复制代码
void SLTPopBack(SLTNode** pphead)
{
	SLTNode* pretail = NULL;//初始化慢指针
	SLTNode* tail = *pphead;
	while (tail->next != NULL)
	{	
		pretail = tail;//待tail指针内容改变前,先赋值给慢指针
		tail = tail->next;
	}
	pretail->next = NULL;//tail的前一个节点含的指针置NULL

	free(tail);
	tail = NULL;
}

方法2

cpp 复制代码
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部分代码改成

cpp 复制代码
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.链表是否只有一个节点?

修正后的代码

cpp 复制代码
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)

cpp 复制代码
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);//检查是否为空链表
	SLTNode* first = *pphead;
	*pphead = first->next;
	first = NULL;
}

注意断言的顺序:先断言pphead,再断言*pphead!

在SList.h中写入该函数的声明

main.c部分代码改为

cpp 复制代码
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);
}
相关推荐
Want5954 分钟前
Python汤姆猫
开发语言·python
Larry_Yanan26 分钟前
QML学习笔记(五十)QML与C++交互:QML中单例C++对象
开发语言·c++·笔记·qt·学习·ui·交互
im_AMBER26 分钟前
算法笔记 09
c语言·数据结构·c++·笔记·学习·算法·排序算法
凯芸呢28 分钟前
Java中的数组(续)
java·开发语言·数据结构·算法·青少年编程·排序算法·idea
竹竹零35 分钟前
JacksonUtil--序列化与反序列化
java·开发语言·windows
AI柠檬1 小时前
几种排序算法的实现和性能比较
数据结构·算法·c#·排序算法
sheji34161 小时前
【开题答辩全过程】以 基于Java的旅游网站的设计与开发为例,包含答辩的问题和答案
java·开发语言·旅游
yue0081 小时前
C# XML文件的读写V2.0
xml·开发语言·c#
SweetCode1 小时前
C++ 实现大数加法
开发语言·c++·算法
Nan_Shu_6141 小时前
学习:JavaScript(5)
开发语言·javascript·学习