(5)数据结构与算法-无空头链表的删、改、查

利用数据找节点

之前有涉及到利用下标找节点

struct Chain* FindMid(struct Chain *pHead, int Index){
	if (NULL == pHead || Index < 0){
		printf("头指针为0or下标无效\n");
		return NULL;
	}
	else{
		int Sign = 0;
		while (NULL != pHead){
			if (Sign == Index)
				return pHead;
			Sign++;
			pHead = pHead->pNext;
		}
		return NULL;  
	}
}

利用数据找节点也很简单
1)定义利用数据找节点的函数

struct Chain*FindData(struct Chain **pHead, int iData){}

2)合法性检测

if (NULL == pHead)
	return NULL;

3)遍历链表,并与要找的比较

	while (NULL != pHead){
		//循环遍历,若相等则是要找的值
		if (pHead->iData == iData)
			return pHead;
		pHead = pHead->pNext;
	}

4)若要是继续执行没有返回pHead那就是没有找到

struct Chain*FindData(struct Chain *pHead, int iData)
{
	if (NULL == pHead)
		return NULL;
	while (NULL != pHead){
		//循环遍历,若相等则是要找的值
		if (pHead->iData == iData)
			return pHead;
		pHead = pHead->pNext;
	}
	return NULL;
}

5)主函数检验

	struct Chain *pTemp = FindData(pHead,3);
	printf("%d ",pTemp->iData );

无空头链表的修改

找到指定节点,修改为指定数据
修改数据,而不是修改指针指向,所以传一级指针就可以
1)定义修改数据的函数

void ModiData(struct Chain *pHead, int IniData, int NewData){}

2) 合法性检测

void ModiData(struct Chain *pHead, int IniData, int NewData){
	if (NULL == pHead)
		printf("不合法错误\n");
	else{}
}

3)替换数据
要先定义指针接住找到的返回值,然后将接住的值修改成新值就可以了
注意:找是从头找,找到第一个要找的值就返回(后面可能还会有相同的值)

void ModiData(struct Chain *pHead, int IniData, int NewData){
	if (NULL == pHead){
		printf("不合法错误\n");
		return;
	}
	else{
		struct Chain *pTemp = FindData(pHead, IniData);
		if (NULL == pTemp)
			printf("查无此节点\n");
		else
			pTemp->iData = NewData;
	}
}

一次性修改多个数据

一次性修改多个,就是把多个相同的数据,修改为其他相同的数据
1)合法性检测

void ModiData(struct Chain *pHead, int IniData){
	if (NULL == pHead ){
		printf("查无此节点");
		return;
	}
}

2)修改多个数据
直接将源地址和要修改的地址比较,系统会从开始到最后都找一遍,找到之后,都修改为目标地址即可。

void ModiData(struct Chain *pHead, int IniData,int NewData){
	if (NULL == pHead ){
		printf("查无此节点");
		return;
	}
	while (NULL != pHead){
		if (pHead->iData == IniData)
			pHead->iData = NewData;
		pHead = pHead->pNext;
	}
}

如何通过调用查找函数来修改多个?
这样的效率就非常低,一般都是用第一个!第二个知道,了解就好!
1)合法性检测

2)第一次查找
用改单个的方法改多个,无非就是将该单个的代码进行循环,就变成改多个的了。先在循环前先立好条件,肯定是查找的节点不为空吧,这样的话,首先我们就要先查找一次,这样查找的节点就不为空了,如下

//第一次找
	struct Chain *pTemp = FindData(pHead,IniData);
	if (pTemp == NULL)
	{
		printf("查无此节点\n");
		return;
	}
	else
		pTemp->iData = NewData;
//循环查找
	while (NULL != pTemp)
	{
		pTemp = FindData(pHead, IniData);
		//接着从此节点的下一个节点开始找
		if (pTemp != NULL)
			pTemp->iData = NewData;
	}

无空头链表的删除

删除头

多层考虑:
1.链表无节点,直接结束!!
2.链表只有一个节点,释放节点,头、尾指针也要赋值为NULL
3.多个节点,记录第一个节点,头指针指向下一个节点,释放记录的节点。若只头指针指向下一个节点的话,之前的节点就找不到了,也无法释放!!

void DeleData(struct Chain **pHead, struct Chain **pTail)
{
//无节点
	if (NULL == *pHead)
		return;
//仅有一个节点
	if ((*pHead)->pNext == NULL)
	{
		free(*pHead); //释放内容
		*pHead == NULL, *pTail == NULL;
	}
//不仅有一个节点	
	else
	{
		struct Chain *pTemp = *pHead;
		*pHead = (*pHead)->pNext;
		free(pTemp);
	}
}

删除尾

多层考虑:
1.链表无节点,直接结束!!
2.链表只有一个节点,释放节点,头、尾指针也要赋值为NULL
3.循环找到尾节点的前一个节点,释放尾节点,尾指针指向上一个节点,新的尾节点的结构体指针赋值为NULL

void DeleTailData(struct Chain **pHead, struct Chain **pTail)
{
	if (NULL == pHead)
	{
		printf("无节点\n");
		return;
	}
	else
	{
		if (NULL == (*pHead)->pNext )
		{
			free(*pTail);
			*pHead == NULL, *pTail == NULL;
		}
		else
		{
			//找尾节点前一个
			struct Chain *pTemp = *pHead; //中间变量
			while (pTemp->pNext !=*pTail)
			{
				pTemp = pTemp->pNext;
			}
			//已找到
			free(pTemp->pNext);
			//尾指针指向上一个
			*pTail = pTemp;
			//尾指针的下一个要赋空
			(*pTail)->pNext = NULL;
		}
	}
}

删除指定数据

多层考虑:
1.参数合法性检测,若为空链表直接返回
2. 找节点,若是头节点,调用头删除;若是尾节点,调用尾删除;其他节点的话,就要循环找到要删除的前一个节点指向当前节点的数据来判断,具体见代码。

void DeleMidData(struct Chain **pHead,struct Chain **pTail,int iData)
{
	if (NULL == *pHead)
		return;
	if ((*pHead)->iData == iData)
		DeleHeadData(pHead,pTail);
	else if ((*pTail)->iData == iData)
		DeleTailData(pHead,pTail);
	else
	{
	//定义中间变量装头指针
		struct Chain *pTemp = *pHead;
	//循环找要修改的前一节点
		while (pTemp->pNext  != *pHead)
		{
		//通过前一节点,指向要释放的节点的值
			if (pTemp->pNext->iData == iData)
				break;
			pTemp = pTemp->pNext;
		}
		//判断pTemp->pNext是否为空,不为空才算找到
		if (pTemp->pNext == NULL)
		{
			printf("未找到");
			return;
		}
		else
		{
		//节点没名字,直接释放会丢失
			struct Chain *pT = pTemp->pNext ;
		//将上一节点的结构体指针指向要释放的节点的下一个节点
			pTemp->pNext = pT->pNext;
			free(pT);
		}
	}
}

删除指定数据的全部节点

同样是修改指针,要调用二级指针;删除链表的多个节点,要遍历链表,碰见相同的就删。
多层逻辑考虑:
1.如果是头或尾,调用删除头或尾的函数
2.如果是中间节点,那就那就调用删除中间节点的函数
3.删除多个,肯定要找多个,就要用到循环去找了,可以调用删除一个的函数,然后再循环。这一环节我们需要用到返回值,用返回值来决定是否还要继续遍历来找要删除的节点,若要删除的节点找完了,那就返回NULL结束循环
1)判断合法性:链表是否为空,为空就不需要遍历

if (NULL == *pHead){
		printf("pHead为空\n");
		return NULL;}

2)如果想删除的节点是头节点,那头指针就指向下一个节点,然后从下一个节点继续遍历寻找,返回新的头即可

	if ((*pHead)->iData == iData)
	{
		DeleHeadData(pHead, pTail);
		return *pHead;
	}

3)如果想删除的节点是尾节点,尾节点在程序逻辑中被删除后,不能直接返回NULL的,因为中间若是存在想删除的节点还没删掉(删除中间节点的代码在下面还未执行),所以要返回头指针继续遍历寻找中间的节点

	else if ((*pTail)->iData == iData)
	{
		DeleTailData(pHead,pTail);
		return *pHead;
	}

4)寻找中间节点,和上面的删除一个节点的函数略有相同

else
	{
		//循环找节点
		struct Chain*pTemp = *pHead;
		while(pTemp->pNext != NULL)
		{
			if (pTemp->pNext->iData == iData)
				break;
			pTemp = pTemp->pNext;
		}
		//此时若已找到,就要判断是否为空,进而进行释放
		if (pTemp->pNext != NULL)
		{
			struct Chain *pT = pTemp->pNext;
			pTemp->pNext = pT->pNext;
			free(pT);
			//返回这个节点,下次直接从这个节点的下一节点遍历
			return pTemp ; 
		}
		else //没找到
		{
			printf("未找到\n");
			return NULL;
		}
	}

上面的返回值为这个 return pTemp->pNext ; 时,当pTemp上的数要被删除时,外侧调用的是头删除(头删除代码块是没有接下一节点代码的,所以要需要删除头或尾的时候会造成断开的情况,即只要不涉及删头或者尾,用这个也可以),若后面不一遍遍从头遍历是与前面连不上的,而 return pTemp ; ,则没调用头删除,后面也不用一次次从头遍历查找,效率非常高

删除一个的函数,已整改完成,对删除一个节点的也完全适用,如下:

struct Chain* ADeleAlliData(struct Chain **pHead,struct Chain **pTail,int iData)
{
	if (NULL == *pHead){
		printf("pHead为空\n");
		return NULL;
	}
	if ((*pHead)->iData == iData){
		DeleHeadData(pHead, pTail);
		return *pHead;
	}
	else if ((*pTail)->iData == iData){
		DeleTailData(pHead,pTail);
		return *pHead;
	}
	else
	{
		//循环找节点
		struct Chain*pTemp = *pHead;
		while(pTemp->pNext != NULL){
			if (pTemp->pNext->iData == iData)
				break; //找到就返回
			pTemp = pTemp->pNext;
		}
		if (pTemp->pNext != NULL){
			struct Chain *pT = pTemp->pNext;
			pTemp->pNext = pT->pNext;
			free(pT);
			return pTemp ;
		}
		else
			return NULL;
	}}

5)删除多个节点
第一步还是参数合法性检测


	//合法性检测
	if (NULL == *pHead)  //链表为空
		return ;

其次,先找一次,将找到的指针传给下一个

//定义中间变量,先找一次
	struct Chain*pTemp =  ADeleAlliData(pHead, pTail, iData);  

最后,利用循环不断往下一个去找,由于pTemp是不断指向要被删除的节点的,所以每次从它开始遍历(之前遍历的都找过了)会提升不少效率!

 //pTemp == NULL就是没找到,直接跳过去
while (pTemp != NULL) 
	{
		//继续找  pTemp 装的是想要删除的节点,
		//我们每次不要都重新开始找,删除后,pTemp会指向下一个节点
		pTemp = ADeleAlliData(&pTemp, pTail, iData);
	}

根据下标删除节点

逻辑和根据数据删除节点相似,只不过一个找的是数据,一个找的是下标
逻辑:
1)合法性检测

if (NULL == *pHead)
		return;

2)判断是不是头节点,是头节点就调用头删除;尾节点的话,就无法判断是不是尾了,所以要当作其他节点进行处理。

//下标为0就是头
if (0 == Index){
		struct Chain *Temp = *pHead;
		*pHead = (*pHead)->pNext;
		free(Temp);
	}

3)其他节点的处理
a. 调用根据下标查找前一节点的函数
b.找到节点

else{
		struct Chain *pTemp = FindIndex(*pHead, Index - 1);
		if (pTemp == NULL)
			return;
		struct Chain *pT = pTemp->pNext;
		pTemp ->pNext  = pT->pNext;
		free(pT);
	}

欢迎吐槽、纠正

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沐鑫本鑫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值