关于在递归中删除链表结点不会导致链表断链的理解

本文探讨了如何使用递归算法删除不带头结点的单链表中所有值为x的结点。王道书中的解决方案通过引用类型避免了寻找前驱结点来修改next域,从而防止断链。讲解了引用类型的特性,并通过实例解释了为何在递归过程中可以直接删除节点而不造成链表断裂。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

        题目来自王道书:设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点。
        这道题在开始看的时候是觉得很简单的,判断是否等于x,然后在L->next进行递归就是了,但是当我看到答案的时候就很懵了(答案如下):

void Del_x_3(Linklist &L,ElemType x)
{
	LNode *p;
	if(L==NULL)
		return;
	if(L->data==x)
	{
		p=L;
		L=L->next;
		free(p);
		Del_x_3(L,x);
	}
	else
		Del_x_3(L->next,x);
}

        在王道书的答案中,在if(L->data==x)的程序段里面,没有寻找前驱结点,来改变next域,直接使用了L=L->next,在代码最后,也为我们强调了这段程序不会断链。
        那首先我们需要了解,什么是断链:在这个问题中,也就是next没有指向它应该指向的地方。但在王道书上的代码,没有找前驱结点改变其next域,这就会造成断链了呀,为什么没有?这就涉及到了void Del_x_3(Linklist &L,ElemType x)在调用中使用了“引用类型”(Linklist &L)。
        什么是“引用类型”,简单来说,就是给你起了个外号,你叫“李**”,别人叫你“小李同学”,这时候“小李同学”和“李**”都是指你,“小李同学”就相当于你的“引用类型”,用程序表示就是ElemType &小李同学=李**,把这个放入实际的代码例子中就相当于int &a=b,这个时候a和b就会指向同一片区域,a和b是这个片区域的不同名字而已。
在这里插入图片描述
        同时在使用引用类型的时候需要注意以下三个规则:
(1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
(2)不能有NULL 引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
(3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。
//如果想要更加深入的了解引用还有引用和指针的关系可以参考这两篇文章引用和指针的区别 引用类型
        讲完引用类型,接下来将为什么在递归中可以使直接删除结点不会导致链表断链。在void Del_x_3(Linklist &L,ElemType x)在调用中使用“引用类型”(Linklist &L)着使得在调用中后一个L与前一个L->next是相同的。我们假设链表元素为{1,2,2,5,6,5,2},我们在其中删除值为2 的元素,在L指向1号元素时,1!=2,因此执行Del_x_3(L->next,x),此时我们将第二轮调用的L称为L1,L1=L->next,同时L1指向了2号元素2= =2,因此需要删除,在执行L=L->next时,相当于L1=L1->next,相当于L->next=L->next->next,这下是不是和我们所熟知的式子一样了。
在这里插入图片描述
如图一样,L的next域(即我红色那一部分)和L1都指向了后继结点,同时,L1和L->next是共享一个数据块的,这两是同一个数据块的不同名字,所以L=L->next在我看来还有另外一个理解,就是L所代表的数据块被L->next所覆盖,而L所代表的数据块正式前驱结点的next域,即L的前驱结点next域也同时被修改了,这样便没有造成断链。之后的也是一样的,可以自己推一下。同时需要注意,在每一次递归后其实与当前L相关的只有本身和前驱结点的next域,与再之前结点并没有什么关系。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值