问题
My recursion skill is pretty rusty. I've been thinking about this problem and searched the forum for a long time but still cannot understand. Right now I'm looking at the recursively reverse a linked list code from Stanford CS ed library.
#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);
}
Now suppose I have a linked list 1->2->3->4. What I cannot understand is the last line, which will set the headRef to 4 eventually, I think it should set the headRef to 2. I tried to execute the function and it printed out:
4
4
4
for the variable rest.
However, if I commented the last line in the the Reverse function out, it still reversed the list but would print
4
3
2.
The second result I can understand, but the first one seemed quite confusing. Does the statement "*headRef=rest" do any thing to the variable rest? What does it keep pointing to 4?
Also, if I pass *headRef instead of **headRef (last line is not commented out), it would print the result
4
3
2
too.
Could anyone please explain to me what happened in the memory? Thanks a million.
回答1:
Before the recursive call to Reverse
we have:
first---|
|
v
1->2->3->4->NULL
^
|
|
rest------
After the recursive call to Reverse
we have:
first---|
|
v
1->2<-3<-4
| ^
v |
NULL |
rest------------
Now we need to fix 2->NULL
to 2->1
by first->next->next=first
.
first---|
|
v
1<-2<-3<-4
| ^ ^
|--| |
|
rest------------
Now we need to fix 1->2
to 1->NULL
by first->next=NULL
.
first---|
|
v
NULL<-1<-2<-3<-4
^
|
|
rest------------
Finally *headRef=rest
so that *headRef
will point to 4
instead of to 1
.
回答2:
What happens here is as because the recursive call passes the address of rest to the local variable headRef, when each recursive call returns, the statement *headRef=rest already changes the address of rest pointer for the statements coming next in the execution flow.
For the linked list 1->2->3->4 :
Let us assume 1 is stored in address 100, 2 in address 200, 3 in address 300 and 4 in address 400.
PART 1: the call Reverse(&rest) [rest points to address 400]
first = 400 rest = NULL
as rest is NULL the execution returns to the point after Reverse(400) call
PART 2: Here first = 300 and rest = 400 after execution of first->next->next=first and first->next=NULL
we have *headRef=rest [rest points to 400]
but this headRef was passed an address of rest=300. So now already for the next step in execution, rest points to 400.
PART 3: Now execution returns to the point after Reverse(300) call
But during forward call [first was 200 and rest was 300] and during return [rest = 400]. HERE'S THE TRICK!!!
after execution of first->next->next=first and first->next=NULL
we have *headRef=rest [rest points to 400]
but this headRef was passed an address of rest=200. So now already for the next step in execution, rest points to 400.
PART 4: Now execution returns to the point after Reverse(200) call
But during forward call [first was 100 and rest was 200] and during return [rest = 400].
after execution of first->next->next=first and first->next=NULL
we have *headRef=rest [rest points to 400]
and as because this is the initial call, the function returns with *headRef having 400 value.
JOB DONE!
来源:https://stackoverflow.com/questions/12230648/recursively-reverse-a-linkedlist-code-in-stanford-csed-library-explanation