对于算法:
使用递归方法,删除无头结点单链表中所有值为x的结点。
考虑如下递归程序:
typedef struct node{
int data;
struct node *next;
}LNode *LinkList;
void del_X(LinkList &L,int x) {
if (L==NULL) return;
if (L->data == x) {
LNode *p = L;
L = L->next; // 仔细思考这行代码
free(p);
del_x(L,x);
}
else {
del_x(L->next,x);
}
}
思考该程序发现,我有如下疑问:
删除结点p时没有更改p前结点的指针,是否会造成链表短链呢?答案是不会。
分析
为了简化,思考链表中某三个结点:1,3,5。现欲删除链表中所有3。
第一次递归:
L指向1结点,递归调用del_X(L->next,x);
注意这里,L->next
是什么?它相当于这个Node*
类型的指针L
所指向的结点的next
域里面的指针,其存储的值为下一个结点的地址。也就是(*L).next
;
第二次递归:
现在进入递归的L实际上是(*L).next
;
注意:当代码执行到L=L->next;
这里问题出现了。这句话其实相当于(*L).next = (*L).next->next;
也就是1指向了5!
注意引用传递
函数void del_X(LinkList &L, int x)
中的LinkList
形参使用引用传递是有原因的。
注意这里的每一个L都是一个指针,其值都来自于链表结点的next域。那么我们现在要更改链表,就必然要使用指针的引用。因为这里我们要更改的是指针本身!而不是指针所指的对象。
后记:
这么写确实能锻炼思维,但是还是希望以后别这样了。这种代码对我这种C渣真的太不友好了。