我正在尝试使用递归来反转链表。我在geeksforgeeks网站上查看了示例程序。他们有一个很好的explanation。但我无法理解每个堆栈展开时* headref会保持什么。在每次堆栈展开期间它是否保持下一个地址,如果是这样的话,那么在所有堆栈展开调用期间其余值是如何相同的。堆栈展开期间第一个值会发生变化,其余值也会变化。为每个堆栈展开更改第一个值时,为什么不会更改静止值。请帮助理解。
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;
}
答案 0 :(得分:0)
一旦'rest list'在递归步骤中被反转,rest
所指向的第一个项目就成了它的最后一项,所以之前的'first'会在后附加那。然后它是最后一项,因此其next
成员变为NULL
。最后,我们通过调用参数返回新头。
答案 1 :(得分:0)
每次递归调用都会更改头部。
每个递归调用都采用子列表[k,n],其中k是先前解析的元素。
第一个条目是[0,n],在上面的代码中是[first,rest]。
最初链接是从第一个到休息。 在每个递归调用休息之前,链接到首先在列表中有一个临时循环(首先指向休息,休息指向第一个)。
然后,在递归调用返回之后,通过删除第一个到休息链接并且先放下第一个休息来杀死循环。 (基本上只保留相反的顺序)。
作为任何单个链表,最后一个元素不需要childern,现在首先是最后一个元素,所以first-> next变为null。
列表的新头是最后一个元素,在这种情况下将是休息,从最深的递归向上传递。
使用迭代方法可以更快,更轻松地实现此算法。
答案 2 :(得分:0)
这种算法的问题是递归调用所需的内存消耗。
你有一个参数指针和两个var指针,每个调用都在内存堆栈的顶部。但这是它工作的原因,并且var没有改变。它没有引用相同的内存区域。
你可以注意到迭代的approch实际上更快更容易。
void iterativeReverse(struct node** head_ref) {
struct node *prev=NULL, *next;
while (*head_ref) {
next=*head_ref->next;
*head_ref->next=prev;
prev=*head_ref;
*head_ref=next;
}
*head_ref=prev;
}