void del_list(LinkList *&L, ElemType x) {
LNode *p = (LNode *)malloc(sizeof(LNode));
if (L == NULL) {
return;
}
if (L->data == x) {
p = L;
L = L->next; //不用访问前驱节点,怎么做到不断链的删除节点
free(p);
del_list(L, x);
}
else {
del_list(L->next, x);
}
}
上述代码的功能是递归的删除以L为首节点指针的单链表中所有值等于x的节点。在百度检索之后,看了一下他们的解析,并不能解答我心中的疑惑,在这里记录一下我的看法。
首先理解一下递归,递归和循环不同的是,递归是栈中操作,每一次的递归相当于一次压栈操作,直到到达递归出口。
例如:一个三个节点的单链表 1->2->3,L指向首节点。
执行 del_list(L,2);
程序栈:
如上图所示,每次经过一次递归,就会进行一次压栈操作,直到递归出口。众所周知,栈是先进后出,所以上述栈在执行的时候会是如下顺序:
由于这个方法是删除值为2的节点,对于不是2节点没有操作,所以主要看第二个操作。
del_list(L->next,2);
if (L->data == x) {
p = L;
L = L->next; //注意将方法参数带入后,原本的语句就会变成L->next = L->next->next
free(p);
del_list(L, x);
}
可以看到,将方法参数 ‘L->next’ 带入,原本会断链的语句现在变成了L->next = L->next->next,明显是正确的,成功删除了值为2的节点且没有断链。
今天回看自己写的博客的时候,虽然递归的执行流程是解释清楚了,但是还是解释递归删除节点不断链的时候还是有些解释不通。
实践是检验真理的唯一途径,我写了上述方法的测试,测试发现编译都成问题,问题出在下面这段代码。
void del_list(LinkList *&L, ElemType x) {
可以注意到方法型参中有 ‘&’ 符号,在之前学习ANSI C中都没有这种用法,表示很疑惑。终究还是见识少了,我搜索之后发现是c++ 中对于引用的申明。
这样就可以说的通了,
del_list(L->next,2);
在上述代码执行的时候,由于方法第一个形参声明的是对于指向LinkList结构体地址的引用,所以在执行
L = L->next; // &L = head->next
在对于引用类型的数据赋值的时候,赋值的是引用的数据的值,即"head->next = L->next;",完成了前驱指针的更新。
int b = 1;
int &a = b;
a = 2;
printf("%d",b);
上述代码输出的无疑会是2。