16

我正在查看斯坦福图书馆的以下代码:

void recursiveReverse(struct node** head_ref)
{
    struct node* first;
    struct node* rest;

    /* empty list */
    if (*head_ref == NULL)
       return;  

    /* suppose first = {1, 2, 3}, rest = {2, 3} */
    first = *head_ref;
    rest  = first->next;

    /* List has only one node */
    if (rest == NULL)
       return;  

    /* put the first element on the end of the list */
    recursiveReverse(&rest);
    first->next->next  = first; 

    /* tricky step -- see the diagram */
    first->next  = NULL;         

    /* fix the head pointer */
    *head_ref = rest;
}

我不明白的是在最后一个递归步骤中,例如如果 list 是 1-2-3-4 现在最后一个递归步骤首先是 1,rest 是 2。所以如果你设置 *head_ref = rest ..这使得列表的头部 2 ?? 有人可以解释一下如何将列表的头部反转为 4 吗?

4

4 回答 4

22

绘制堆栈跟踪...

Intial - {1,2,3,4}
Head - 1
Rest = 2,3,4
Recurse(2,3,4)
Head = 2
Rest = 3,4
Recurse(3,4)
Head = 3 
Rest = 4
Recurse (4)
Head = 4
Rest = null //Base Case Reached!! Unwind.

So now we pick up 
Recurse(3,4)
Head = 3 
Rest = 4
// Return picks up here
first->next->next  = first; 
so list is:
3,4,3
// set head to null,
null ,4,3,
//Off with his head!
4,3
Return

Now we're here
Recurse(2,3,4)
Head = 2
Rest = 3,4
Previous return leaves state as:
Head = 2  //But Head -> next is still 3! -- We haven't changed that yet..
Rest = 4,3  
Head->next is 3, 
Head->next->next = 2 makes the list (actually a tree now)
4->3->2
   ^
   |
   2
And chop off the head leaving
4->3->2
and return.

Similarly, do the last step which will leave
4->3->2->1
      ^
      |
      1
and chop off the head, which removes the one. 
于 2010-03-12T17:49:37.900 回答
19

考虑一下列表:

   1  ->  2  ->  3  ->  4 -> NULL
   ^      ^
   |      |
 first   rest

Wherefirst指向第一个节点,rest 指向 . 旁边的节点first

由于列表不为空且列表不包含一个节点,我们进行递归调用reverse以反转 指向的列表rest。这是在反转列表的其余部分后列表的外观:

   1  ->  2  <-  3  <-  4
   ^      |             ^
   |     NULL           |
 first                 rest

rest现在所见,指向在列表4开头和2结尾的反向列表。节点的下一个指针2NULL

现在我们需要将第一个节点附加到反向剩余列表的末尾。要将任何内容附加到列表的末尾,我们需要访问列表的最后一个节点。在这种情况下,我们需要访问反向剩余列表的最后一个节点。看图,first -> next指向最后一个节点 reversed-rest 列表。因此first -> next -> next将是反向剩余列表的最后一个节点的下一个指针。现在我们需要指出它,first所以我们这样做:

first -> next -> next = first;

在此步骤之后,列表如下所示:

   1  <-  2  <-  3  <-  4
   ^  ->                ^
   |                    |
 first                 rest

现在next列表的最后一个节点的字段必须是NULL。但现在情况并非如此。next最后一个节点( node )的字段1指向它之前的节点( node 2)。为了解决这个问题,我们这样做:

first -> next = NULL;

在此之后,列表如下所示:

NULL <- 1  <-  2  <-  3  <-  4
        ^                    ^
        |                    |
      first                 rest

正如所见,列表现在正确地反转,rest指向反转列表的头部。

我们需要返回新的头指针,以便更改反映在调用函数中。但这是一个void函数,并head作为双指针传递,因此更改的值*head将使调用函数看到更改后的头部:

*head = rest;
于 2011-02-25T09:08:32.717 回答
7

其余的不是2,而是2 -> 3 -> 4,递归地反转。之后我们设置*head_refrest,现在是(递归反转!)4 -> 3 -> 2

这里重要的一点是,尽管firstrest都具有相同的类型,即node*,它们在概念上根本不同:first指向一个单个元素,而rest指向一个元素的链表。此链表在分配给 之前递归地反转*head_ref

于 2010-03-12T17:09:21.270 回答
0

我最近写了一个递归方法来反转 ruby​​ 中的链表。这里是:

def reverse!( node_1 = @head, node_2 = @head.link )
    unless node_2.link 
        node_2.link = node_1
        @head = node_2
        return node_1
    else 
        return_node = reverse!(node_1.link, node_2.link)
        return_node.link = node_1
        node_1.link = nil
        return node_1
    end
    return self
end
于 2013-11-07T01:23:44.080 回答