将头部引用标记为链接列表的尾部

时间:2015-02-01 19:24:30

标签: c linked-list

反转链表的迭代方法是非常简单的方法。我尝试通过以下链接了解递归方式

http://www.geeksforgeeks.org/write-a-function-to-reverse-the-nodes-of-a-linked-list/

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;   

    /* reverse the rest list and put the first element at the end */
    recursiveReverse(&rest);
    first->next->next  = first;  

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

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

我们首先将指针移动到链表的尾部。 在堆叠展开期间,我们反向缝合链接。 但对于所有堆栈展开调用,* headref = rest。因此,首先在堆栈展开到前一个堆栈值时进行更改,为什么其余的堆栈值也没有变化。我创建了4个节点并通过gdb查看了这些值。堆栈展开期间的其余值保持不变,但第一个值正在变化。为什么休息不变。

1 个答案:

答案 0 :(得分:1)

虽然在改变指针和值方面进行思考是一种好方法 考虑迭代程序,这是一个令人困惑的方式来看待 递归程序,因为每个递归调用都会创建自己的本地 变量,都具有相同的名称,但可能有不同的值。

使用递归函数,假设它对于大小为n的输入正常工作更有帮助,然后验证其大小为n+1的输入的正确性。如果"基础案例" (大小0或1)被覆盖,这证明它适用于所有输入

在您的情况下,我们假设recursiveReverse适用于长度为3的列表,并让我们为其提供长度为4 a->b->c->d的列表 在recursiveReverse(&p)

中调用p=a

first->nextrest都是b,因此指向3个元素的列表b -> c -> d,因此(根据我们的假设) recursiveReverse(&rest)会正确撤消此列表。之后 来电,rest已更改了值(从bd),现在指向此反转列表d->c->b

first->next仍然是与调用之前相同的指针b,因此现在指向列表的 end 。 因此,first->next->next = firstfirst附加到此反转列表的末尾,然后变为d->c->b->a) 由于first现在是列表的末尾,我们现在需要first->next = NULL。最后一步是更改*head_ref(从a更改为d),因此,从recursiveReverse(&p)返回后,p将从{{1}更改}到列表的新头,a

这表明只要函数对n元素正常工作 列表,它适用于n + 1个元素列表。基础案例很简单, 所以这表明它适用于所有列表。

现在,为什么您没有在调试器中看到d更改值?因为 它的值只能通过函数调用来改变 rest。在递归调用之前 recursiveReverse(&rest)它有一个值,从它返回后它有 另外,当你踩进和退出每个函数调用时,你都不会看到它发生变化。更改其值的赋值实际上是函数返回之前的最后一个(recursiveReverse),但是在此堆栈框架中,受理人称为*head_ref = rest,而不是head_ref(因为它在调用者的堆栈框架)

这是"相同的名称,但不同的值"我上面提到的困惑。