在C中递归删除单个链表

时间:2018-01-26 00:22:43

标签: c recursion linked-list

它看起来没有重复的问题......所以我想要一个函数来释放单个链表中的所有节点,我想以递归方式进行。我想出了一个我觉得它会起作用的关闭,但事实并非如此。似乎在删除了一个节点之后,上层堆栈函数将不会以递归方式为借口。我想知道如何修改代码以使其工作。

#include <stdlib.h>
#include<stdio.h>
#include<stdlib.h>

struct Node 
{
  int data;
  struct Node *next;
};

void ft_list_clear(struct Node *begin_list)
{
    if ((begin_list->next))
      ft_list_clear(begin_list->next);
    if(!(begin_list->next))
    {
      free(begin_list);
      begin_list = NULL;
    }
}

int main()
{
  struct Node* head = NULL;
  struct Node* second = NULL;
  struct Node* third = NULL;

  // allocate 3 nodes in the heap  
  head  = (struct Node*)malloc(sizeof(struct Node)); 
  second = (struct Node*)malloc(sizeof(struct Node));
  third  = (struct Node*)malloc(sizeof(struct Node));

  head->data = 1; //assign data in first node
  head->next = second; // Link first node with second   

  second->data = 2; //assign data to second node
  second->next = third;  

  third->data = 3; //assign data to third node
  third->next = NULL;

  ft_list_clear(head);
  return 0;
}

5 个答案:

答案 0 :(得分:3)

你非常接近

col-md-4

解释代码

第一个void ft_list_clear(struct Nude *list) { if (!list) { return; } ft_list_clear(list->next); list->next = null; free(list); } 检查列表当前是否为if,如果是,则退出递归。

如果列表不是null递归调用该函数。 这将重复到列表null的末尾。 然后由于null已被递归调用清除,您可以在此调用中将其设置为next(因为这会清除所有内容,因此不是必需的)。 最后实际上null此节点在返回上一个调用之前(此节点的父节点)。

如果需要,您也可以按相反的顺序进行删除

free

相同的原则只是在转到下一个节点之前删除此节点。这意味着您不需要修复void ft_list_clear(string Node *list) { if (!list) { return; } struct Node *next = list->next; free(list); ft_list_clear(next); } 指针,但您需要先复制它们,这样就不会丢失引用。

答案 1 :(得分:1)

我认为这是因为你只是释放节点,但是你错过了next成员的无效。试试这个。我没有这么好运。

void ft_list_clear(struct Node *begin_list)
{
    if ((begin_list->next))
    {
      ft_list_clear(begin_list->next);
      begin_list->next = NULL; // <-- you should nullify the next of the current after you free the node which it points to.
    }
    if(!(begin_list->next)) // <-- even if the next node was deleted, this won't run if you didn't nullify begin_list->next
    {
      free(begin_list);
      begin_list = NULL;
    }
}

答案 2 :(得分:1)

这个问题

void ft_list_clear(struct Node *begin_list)
{
    if ((begin_list->next))
      ft_list_clear(begin_list->next);
    if(!(begin_list->next))
    {
      free(begin_list);
      begin_list = NULL;
    }
}

是:

  • 在第一次通话中,begin_list等于head
  • head->next不是NULL,因此执行ft_list_clear(second)
  • second->next不是NULL,因此执行ft_list_clear(third)
  • third->nextNULL,因此发生了free(third)begin_list = NULL line在这里什么也没做,没有意义。
  • 第三次迭代返回第二次。下一行要执行

    if(!(begin_list->next))
    

    begin_list->next NULL(它只是free d),因此条件评估为false和{{1 }} 未执行。

  • 第一次迭代也是如此。

这是可行的递归:

free

答案 3 :(得分:0)

`void ft_list_clear(struct Node * begin_list)

{
    if ((begin_list->next))
      ft_list_clear(begin_list->next);

    free(begin_list);
    begin_list = NULL;
    printf("God bless America");
}`

希望,如果上帝保佑美国三次,你的代码正在运行,我已经对你的代码进行了一些修改,而我所做的就是删除第二个if语句,因为通常,我们不需要递归(I')我并不是说如果声明我们不需要多于一个)。自己测试,你会明白为什么会这样。希望它有所帮助。

答案 4 :(得分:0)

递归删除链接是 坏主意 。每个递归调用都需要一个堆栈帧,无论是在下降还是递增递归时释放列表节点内存,都需要O(n)内存来进行简单的操作。每个堆栈调用都需要本地变量存储,返回指针空间,前一个堆栈帧指针以及可能的其他内容(每个节点至少12-24个字节)。

最好迭代列表。我提供了三种免费变体(迭代,两个递归,一个自由下降的节点,一个自由的上升节点)。

#include <stdlib.h>
#include <stdio.h>

typedef struct Node 
{
    int data;
    struct Node* next;
} node_t;

long list_clear_iter(node_t* p) {
    if(!p) return 0;
    long n = 0; //count;
    for( ; p->next; ) {
        node_t* fp = p; //free this
        p = p->next;
        free(fp);
        ++n;
    }
    return n;
}

//list clear, recursive, (pre)free
long ft_list_clear_pr(node_t* p) {
    if(!p) return 0;
    node_t* np = p->next;
    free(p); //free on descend
    long n = ft_list_clear_pr(np);
    return(n+1);
}
//list clear recursive, free(post)
long ft_list_clear_rp(node_t* p) {
    if(!p) return 0;
    long n = ft_list_clear_rp(p->next);
    free(p); //free on ascend
    return(n+1);
}