单链表的查找销毁,指定位置的插入删除


前言

本文承接上篇对单链表的构建和删除插入,将要详细讲述有关单链表的查找销毁,以及如何在指定位置附近对数据进行添加和删除,本文中会用到上一篇blog中的相关函数,忘记的友友可以到上一篇查看~

必看:本文中所有代码的具体实现都可以在首页的gitee链接中免费查看获取!!!


一、查找

实现思路:由于单链表只能从表头开始一个一个往后找,所以在定义查找函数时,肯定要有指向表头的一级指针(此时表头直接指向链表的实际首元结点,即存储第一个数据元素的结点)和查找的结点中的数据;我们找到这个结点肯定要进行使用,因此我们返回的数据类型应该是一级指针类型(即返回结点的地址);查找成功我们就返回结点地址,找不到则返回NULL

SLTN* SLTFind(SLTN* phead, SLTdata x);
//在Slist.h头文件中声明 

函数的具体实现:

注意:我们通常不直接使用头指针,而是重新定义一个变量pcur来实现遍历查找,此处是习惯,大多数时候是为了避免改变头指针而造成报错(具体后面会讲到)

//查找
SLTN* SLTFind(SLTN* phead, SLTdata x)//查找的节点中的值
{
	SLTN* pcur = phead;
	while (pcur)
	{
		if (pcur->data == x)
		{
			//printf("找到啦!\n");在测试函数中实现
			//break;可以直接返回pcur
			return pcur;
		}
		pcur = pcur->next;
	}

	return NULL;//将找到的数据的地址返回
}

 下面我们在test.c中进行函数的测试

void test()
{
SLTN* plist = NULL;
//首先先向单链表中插入数据
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 2);
SLTPushBack(&plist, 3);
SLTPushBack(&plist, 4);
//进行查找
SLTN* find=SLTFind(plist, 1);
if (find == NULL)
	printf("没找到!\n");
else
	printf("找到了\n");
}

 

 

二、销毁

单链表销毁的原因主要是为了释放资源,避免内存泄漏。

函数实现思路:想要销毁单链表,肯定要利用到二级指针,这样才能够释放我们各个结点的内存(要改变结点的地址),此时我们的链表不能为空,二级指针同样也不能为空。要将所有的结点全部释放我们就要用到while循环(不清楚循环次数),最后要记得把表头置为NULL!

此处同样是出于习惯不直接改变头指针

//销毁链表(销毁一个一个结点)
void SListDesTory(SLTN** pphead)
{
	assert(pphead && *pphead);
	SLTN* pcur = *pphead;
	while (pcur)
	{
		SLTN* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

也可以对代码进行一下优化: 直接利用头指针进行销毁

void SListDesTory(SLTN** pphead)
{
	assert(pphead && *pphead);
	while (pphead)
	{
		SLTN* next = (*pphead)->next;
		free(*pphead);
		*pphead = next;
	}
	*pphead = NULL;
}

三、在指定位置处插入数据

  • 在指定位置前插入

函数实现思路:此时我们先来考虑一种特殊情况,如果pos指向的是我们的首元素,那在pos之前插入肯定要改变我们头指针的指向,这时就必须用到指向头指针的指针;此时我们肯定也要将pos作为函数的参数因为我们得知道该结点具体的地址,最后再是我们需要插入的元素数据。

如图所示:此时这种情况插入数据==头插,我们可以直接引用头插函数

一般情况如下,知道pos的位置,但我们需要用到pos前一个结点的地址prev,才能实现结点的插入,因此我们得先利用循环找到pos的前一个结点

综上,函数实现如下

//在指定位置之前插入数据
void SLTInsert(SLTN** pphead, SLTN* pos, SLTdata x)
{
	//首先pos不能为NULL,否则根本找不到这个位置,链表同样不能为空
	assert(pos && pphead && *pphead);
	SLTN*prev = *pphead;
	//找到pos前面的节点
	if (pos == *pphead)
	{
		//直接利用头插
		SLTPushFront(pphead, x);
	}
	else
	{
		while ((prev)->next != pos)
			prev = (prev)->next;
		SLTN* newnode = SLBuyNode(x);//别忘记给新结点申请空间
		prev->next = newnode;//将该位置的next存储新节点的地址
		newnode->next = pos;

	}
	

}

 

  • 在指定位置后插入

函数实现思路:在指定位置后插入非常简单,pos后一个结点的地址我们是容易找到的,此时我们的函数参数,只需要pos以及需要插入的数据即可

//在指定位置之后插入数据
void SLTInsertafter(SLTN* pos, SLTdata x)
{
	assert(pos);//pos不能为NULL
	SLTN* newnode= SLBuyNode(x);
//注意此处的顺序不可调换,否则pos->next会被修改
	newnode->next = pos->next;
	pos->next = newnode;
}

 四、在指定位置处删除数据

  • 删除pos处的结点

函数实现思路:

首先先考虑特殊情况,假如单链表中只有一个结点,此时我们应该直接将头结点释放,则此时要改变头节点要用到二级指针

一般情况下,我们只需要先将pos的前后两个结点链接起来,再将pos释放掉即可

//删除pos节点
void SLTErase(SLTN** pphead, SLTN* pos)
{
	assert(pphead && *pphead && pos);
	SLTN* prel = *pphead;
	//分pos是头结点和不是头结点的情况
	if (pos == *pphead)
	{
		*pphead= (*pphead)->next;//第二个结点要变成新的头结点
		free(pos);//此时*pphead已经改变了指向,可以直接释放pos
	}
	else
	{
		while (prel->next != pos)
		{
			prel = prel->next;//首先找到pos前面的节点
		}
		prel->next = pos->next;//将pos前后两个结点相连
		free(pos);
		pos = NULL;//pos指针不再使用置为NULL

	}
	
}
  • 删除pos之后的结点

函数实现思路:找到pos之后的结点的地址,先将pos和删除结点之后的结点相连,再将删除处的结点释放,此时我们只需要用到pos即可

//删除pos之后的结点
void SLTEraseAfter(SLTN* pos)
{
	assert(pos&&pos->next);//pos的下一个结点也不能为空,否则不能删除
	SLTN* del = pos->next;
	pos->next = del->next;//注意此处不能直接连等,否则后面找不到删除处结点的地址了!!!
	free(del);
	del = NULL;
}

总结

本文总结了单链表查找销毁,指定位置删除插入的一系列操作,如果有任何更好的方法和建议欢迎大家在评论区下方留言

  • 51
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值