使用C中的递归来反转链表

时间:2015-02-12 15:01:16

标签: c linux

我正在尝试使用递归来反转链表。我在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;             
}

3 个答案:

答案 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;
}