我的递归技巧非常生疏。我一直在考虑这个问题,并在论坛上搜索了很长时间但仍然无法理解。现在我正在寻找递归反转来自Stanford CS ed库的链表代码。
#include <stdio.h>
struct Node {
int x;
struct Node *next;
};
void Reverse(struct Node ** headRef){
struct Node* first;
struct Node* rest;
if(*headRef==NULL)
return;
first= *headRef;
rest= first->next;
if(rest==NULL)
return;
Reverse(&rest);
printf("Rest%d\n", (rest)->x); // I added this line to print rest
first->next->next=first;
first->next=NULL;
*headRef=rest;
}
void printList(struct Node* head){
if(!head)
return;
else{
printf("%d ", head->x);
printList(head->next);
}
}
void main(){
struct Node *head;
struct Node * node1= (struct Node*) malloc(sizeof(struct Node));
struct Node * node2= (struct Node*) malloc(sizeof(struct Node));
struct Node * node3= (struct Node*) malloc(sizeof(struct Node));
struct Node * node4= (struct Node*) malloc(sizeof(struct Node));
head= node1;
node1->next=node2;
node1->x=1;
node2->x=2;
node3->x=3;
node4->x=4;
node2->next=node3;
node3->next=node4;
node4->next=NULL;
Reverse(&head);
}
现在假设我有一个链表1-&gt; 2-&gt; 3-&gt; 4。我无法理解的是最后一行,它最终将headRef设置为4,我认为它应该将headRef设置为2.我试图执行该函数并将其打印出来:
4
4
4
表示变量rest。
但是,如果我在反转功能中注释了最后一行,它仍然会反转列表但会打印
4
3
2。
我能理解的第二个结果,但第一个结果似乎很混乱。声明“* headRef = rest”是否对变量rest做了什么?它一直指向4?
另外,如果我传递* headRef而不是** headRef(最后一行没有注释掉),它会打印结果
4
3
2
太。
有人可以向我解释记忆中发生了什么吗?太感谢了。
答案 0 :(得分:2)
在递归致电Reverse
之前,我们有:
first---|
|
v
1->2->3->4->NULL
^
|
|
rest------
在递归调用Reverse
后,我们有:
first---|
|
v
1->2<-3<-4
| ^
v |
NULL |
rest------------
现在我们需要2->NULL
将2->1
修改为first->next->next=first
。
first---|
|
v
1<-2<-3<-4
| ^ ^
|--| |
|
rest------------
现在我们需要1->2
将1->NULL
修改为first->next=NULL
。
first---|
|
v
NULL<-1<-2<-3<-4
^
|
|
rest------------
最后*headRef=rest
,以便*headRef
指向4
而不是1
。
答案 1 :(得分:0)
这里发生的是因为递归调用将 rest的地址传递给局部变量headRef ,当每次递归调用返回时,语句* headRef = rest已经更改执行流程中接下来的语句的rest指针的地址。
对于链接列表1-&gt; 2-&gt; 3-&gt; 4:
我们假设1存储在地址100中,2表示存储在地址200中,3表示存储在地址300中,4表示存储在地址400中。
第1部分: 调用Reverse(&amp; rest)[rest points to address 400]
首先= 400 rest = NULL
当rest为NULL时,执行返回到Reverse(400)调用之后的点
第2部分: 这里首先= 300,休息= 400 在执行first-&gt; next-&gt; next = first和first-&gt; next = NULL
之后我们有* headRef =休息[休息点为400]
但是这个headRef被传递了一个rest = 300的地址。所以现在已经为下一步执行, 休息点指向400。
第3部分: 现在执行返回到Reverse(300)调用
之后的点但是在前锋召唤期间[首先是200而休息是300]并且在回归期间[休息= 400]。 这是罢工!!!
执行first-&gt; next-&gt; next = first和first-&gt; next = NULL
我们有* headRef =休息[休息点为400]
但是这个headRef被传递了一个rest = 200的地址。所以现在已经为下一步执行, 休息点指向400.
第4部分: 现在执行返回到Reverse(200)调用
之后的点但是在前锋召唤期间[首先是100而休息是200]并且在回归期间[休息= 400]。
执行first-&gt; next-&gt; next = first和first-&gt; next = NULL
我们有* headRef =休息[休息点为400]
因为这是初始调用,函数返回* headRef,其值为400。
工作完成!