反转链表的迭代方法是非常简单的方法。我尝试通过以下链接了解递归方式
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查看了这些值。堆栈展开期间的其余值保持不变,但第一个值正在变化。为什么休息不变。
答案 0 :(得分:1)
虽然在改变指针和值方面进行思考是一种好方法 考虑迭代程序,这是一个令人困惑的方式来看待 递归程序,因为每个递归调用都会创建自己的本地 变量,都具有相同的名称,但可能有不同的值。
使用递归函数,假设它对于大小为n
的输入正常工作更有帮助,然后验证其大小为n+1
的输入的正确性。如果"基础案例" (大小0或1)被覆盖,这证明它适用于所有输入
在您的情况下,我们假设recursiveReverse
适用于长度为3的列表,并让我们为其提供长度为4 a->b->c->d
的列表
在recursiveReverse(&p)
p=a
first->next
和rest
都是b
,因此指向3个元素的列表b -> c -> d
,因此(根据我们的假设)
recursiveReverse(&rest)
会正确撤消此列表。之后
来电,rest
已更改了值(从b
到d
),现在指向此反转列表d->c->b
first->next
仍然是与调用之前相同的指针b
,因此现在指向列表的 end 。
因此,first->next->next = first
将first
附加到此反转列表的末尾,然后变为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
(因为它在调用者的堆栈框架)
这是"相同的名称,但不同的值"我上面提到的困惑。