我很难理解此递归代码的工作原理,我已经制作了图纸并通过gdb
运行了代码。
void RecursiveReverse(struct node** headRef)
{
struct node* first;
struct node* rest;
if (*headRef == NULL) return; // empty list base case
first = *headRef; // suppose first = {1, 2, 3}
rest = first->next; // rest = {2, 3}
if (rest == NULL) return; // empty rest base case
RecursiveReverse(&rest); // Recursively reverse the smaller {2, 3} case
// after: rest = {3, 2}
first->next->next = first; // put the first element on the end of the list
first->next = NULL;
*headRef = rest; // fix the head pointer
}
我了解到,在构建递归调用堆栈时,一旦列表仅包含{3},空的休息基本情况,if (rest == NULL)
的第一个是true
时间。
此后,递归调用堆栈开始中断,并以{2,3},
首次命中first->next->next = first;
。
在执行此行之前,在gdb
中输出:
(gdb)p *first
{data = 2, next = 0x1003001f0}
(gdb) p *rest
{data = 3, next = 0x0}
执行此行后,
(gdb) p *rest
{data = 3, next = 0x1003000a0}
第二次继续执行代码以击中first->next->next = first;
:
(gdb) p **head_ref
{data = 1, next = 0x1003000a0}
(gdb) p *rest
{data = 3, next = 0x1003000a0} // expected p *rest to be 2
在这里,我期望本地指针rest
指向节点2,因为在建立递归调用栈时,**headRef
指向节点1并在行rest = first->next;
之后被执行{ {1}}指向节点2。
执行rest
之后,*headRef = rest;
是否应该指向节点2?
怎么会丢失本地状态,而其余状态指向节点3?
答案 0 :(得分:2)
让我们假设您有一个列表,其余部分已经被撤消。
在反转其余部分之前,列表具有此结构
first -> first_of_rest -> second_of_rest->...->nth_of_rest->nullptr
反转其余部分后,您将得到
first -> nullptr <- first_of_rest <- second_of_rest <-...<-nth_of_rest
| |
________________________________________________________
the rest part of the list
因此,节点first
的下一个数据成员指向first_of_rest
,而节点first_of_rest
的下一个数据成员“指向” nullptr。
因此,我们现在需要做的是将节点first_of_rest
的数据成员设置为指向节点first
first->next->next = first;
abd将节点first
的下一个数据成员设置为“指向” nullptr。
first->next = NULL;
因此我们有
nullptr <-first <- first_of_rest <- second_of_rest <-...<-nth_of_rest
答案 1 :(得分:0)
这是简化的伪代码。基本上是这样的:
RecursiveReverse(head):
if head is empty:
return
RecursiveReverse(head->next)
// When we come here, the whole list except the first
// element has been reversed. So all that's left to do
// is to reverse the final step
head->next->next = head
head->next = NULL
最重要的是在递归调用之后,除了第一个元素之外的整个列表都被反转了。