C 递归反向链表

C 递归反向链表,c,recursion,linked-list,reverse,singly-linked-list,C,Recursion,Linked List,Reverse,Singly Linked List,我很难理解这个递归代码是如何工作的,我已经通过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-&g

我很难理解这个递归代码是如何工作的,我已经通过
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},那么如果(rest==NULL)第一次为
true
,则空的rest基本大小写


在此之后,递归调用堆栈开始中断并点击
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行之后,已执行
rest
指向节点2

之后*headRef=rest,是否应该
headRef
指向节点2


为什么本地状态会丢失,而其余部分指向节点3?

这里是简化的伪代码。它基本上是这样工作的:

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

这里要认识到的最重要的一点是,在递归调用之后,除了第一个元素外,整个列表都已反转。

假设您有一个列表,它的其余部分已经反转

在反转其余部分之前,列表具有此结构

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
abd将节点
first
旁边的数据成员设置为“指向”nullptr

first->next = NULL;
因此,我们有

nullptr <-first <- first_of_rest <- second_of_rest <-...<-nth_of_rest

NulLPTR最难的部分是接受“<代码>递归sivReVSE(/REST)”的概念,它实际上与其余的相反。@ HasLoValDOS在列表只有两个元素时就足以考虑其中一个基本情况。在反转其余部分之后,当列表看起来像<代码> 1>2NeX/<代码>包含<代码> null < /代码>时,为什么不行
*headRef=rest
*headRef
更改为指向节点2,就像在列表仅包含{2,3}时将
*headRef
更改为指向节点3一样?
rest怎么总是等于{3,…}
之后呢?@HasloVardos头部是通过引用传递的。参见函数参数声明结构节点**headRef。函数的最后一个语句*headRef=rest;因此,只有在基本情况{2,3}中,
*headRef=rest
实际修改head,使其指向rest
rest等于3
,之后这个赋值操作就变得不相关了,因为它做了同样的事情?
nullptr <-first <- first_of_rest <- second_of_rest <-...<-nth_of_rest