C 使用递归删除链表中出现的所有数字

C 使用递归删除链表中出现的所有数字,c,algorithm,recursion,linked-list,C,Algorithm,Recursion,Linked List,我想写一个程序,使用递归从一个简单的链表中删除一个数字的所有匹配项,所以我尝试了,但我遇到了问题:我写的程序删除了列表中的所有匹配项,但它不删除一个存在于开始的匹配项存在于第一个节点,下面是C中的代码: typedef struct list { int data; struct list *next; } list; list *delete(int x, list *head) { if (head->next == NULL) return

我想写一个程序,使用递归从一个简单的链表中删除一个数字的所有匹配项,所以我尝试了,但我遇到了问题:我写的程序删除了列表中的所有匹配项,但它不删除一个存在于开始的匹配项存在于第一个节点,下面是C中的代码:

typedef struct list {
    int data;
    struct list *next;
} list;

list *delete(int x, list *head) {
    if (head->next == NULL)
        return head;
    list *newnode = delete(x, head->next);
    if (newnode->data == x) {
        head->next = head->next->next;
        free(newnode);
    }
    return head;
}
我希望有人能帮助我改进算法,提前谢谢。

此代码:

    if(head->next == NULL)
        return head;
显式使函数返回的任何1元素列表保持不变。这就产生了你所描述的问题,因此没有任何意义

我想应该可以递归地对列表元素进行删除,尽管这肯定不是一种常见/典型/好的方法

这可能有效,但未经测试:

list * delete(list *head, int value)
{
  if (head == NULL)
    return NULL;
  if (head->data == value)
  {
      list * tail = head->next;
      free(head);
      return delete(tail, value);
  }
  // List was not empty and did not start with the value,
  // so set the tail of the list to the tail without the value.
  head->next = delete(head->next, value);
  return head;
}
此代码:

    if(head->next == NULL)
        return head;
显式使函数返回的任何1元素列表保持不变。这就产生了你所描述的问题,因此没有任何意义

我想应该可以递归地对列表元素进行删除,尽管这肯定不是一种常见/典型/好的方法

这可能有效,但未经测试:

list * delete(list *head, int value)
{
  if (head == NULL)
    return NULL;
  if (head->data == value)
  {
      list * tail = head->next;
      free(head);
      return delete(tail, value);
  }
  // List was not empty and did not start with the value,
  // so set the tail of the list to the tail without the value.
  head->next = delete(head->next, value);
  return head;
}
如果没有,它将删除第一个节点上存在的引用开始时存在的引用

这是因为以下几行:

如果只返回一个元素,而不管理它可以包含要删除的数据这一事实,则返回该元素

您不需要有delete的递归定义,最糟糕的是使用非终端递归

还可以添加工作函数以检查执行情况:

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

typedef struct list {
  int data;
  struct list* next;
} list;

list* delete(int x, list* head)
{
  list ** p = &head;

  while (*p != NULL) {
    if ((*p)->data == x) {
      list * d = *p;

      *p = (*p)->next;
      free(d);
    }
    else
      p = &(*p)->next;
  }
  return head;
}

void print(list * l)
{
  if (l == NULL)
    puts("<empty>");
  else {
    do  {
      printf("%d ", l->data);
      l = l->next;
    } while (l != NULL);
    putchar('\n');
  }
}

list * make(int data, list * next)
{
  list * l = malloc(sizeof(list));

  l->data = data;
  l->next = next;
  return l;
}

int main(int argc, char ** argv)
{
  list * head = make(1, make(2, make(1, NULL)));

  print(head);
  head = delete(1, head);
  print(head);
  head = delete(2, head);
  print(head);

  return 0;
}
汇编和执行:

/tmp % gcc -Wall l.c
/tmp % ./a.out
1 2 1 
2 
<empty>
/tmp % 
在valgrind下:

如果没有,它将删除第一个节点上存在的引用开始时存在的引用

这是因为以下几行:

如果只返回一个元素,而不管理它可以包含要删除的数据这一事实,则返回该元素

您不需要有delete的递归定义,最糟糕的是使用非终端递归

还可以添加工作函数以检查执行情况:

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

typedef struct list {
  int data;
  struct list* next;
} list;

list* delete(int x, list* head)
{
  list ** p = &head;

  while (*p != NULL) {
    if ((*p)->data == x) {
      list * d = *p;

      *p = (*p)->next;
      free(d);
    }
    else
      p = &(*p)->next;
  }
  return head;
}

void print(list * l)
{
  if (l == NULL)
    puts("<empty>");
  else {
    do  {
      printf("%d ", l->data);
      l = l->next;
    } while (l != NULL);
    putchar('\n');
  }
}

list * make(int data, list * next)
{
  list * l = malloc(sizeof(list));

  l->data = data;
  l->next = next;
  return l;
}

int main(int argc, char ** argv)
{
  list * head = make(1, make(2, make(1, NULL)));

  print(head);
  head = delete(1, head);
  print(head);
  head = delete(2, head);
  print(head);

  return 0;
}
汇编和执行:

/tmp % gcc -Wall l.c
/tmp % ./a.out
1 2 1 
2 
<empty>
/tmp % 
在valgrind下:


代码中存在多个问题:

您在不首先检查head是否为NULL的情况下解除对其的引用。该函数无法处理空列表。 如果列表中只有一个元素,则显式返回head节点而不测试其值。 在head->next上递归后,只测试列表的第二个元素。因此,第一个元素从未经过测试。 下面是一个修改版本,它只测试第一个节点,并递归列表的其余部分:

列表*删除点x,列表*标题{ 如果head==NULL 回流头; 如果磁头->数据==x{ 列表*节点=头; 头部=头部->下一步; 自由节点; 返回deletex,head; } head->next=deletex,head->next; 回流头; }
代码中存在多个问题:

您在不首先检查head是否为NULL的情况下解除对其的引用。该函数无法处理空列表。 如果列表中只有一个元素,则显式返回head节点而不测试其值。 在head->next上递归后,只测试列表的第二个元素。因此,第一个元素从未经过测试。 下面是一个修改版本,它只测试第一个节点,并递归列表的其余部分:

列表*删除点x,列表*标题{ 如果head==NULL 回流头; 如果磁头->数据==x{ 列表*节点=头; 头部=头部->下一步; 自由节点; 返回deletex,head; } head->next=deletex,head->next; 回流头; }
有点离题挑剔:请不要使用术语C/C++。没有这样的语言,只有两种非常不同的语言C和C++。如果你用C语言编程,那么只标记C语言标记。使用递归迭代链表有什么意义?请提供一个你没有删除的链接,因为行ifhead->next==NULL返回head;在这里使用递归是完全错误的。1.效率较低。2如果你的链表很长,你会遇到麻烦。3.迭代版本更容易编写。扔掉这个函数,在没有递归的情况下正确地重写它。有点离题:请不要使用术语C/C++。没有这样的语言,只有两种非常不同的语言C和C++。如果你用C语言编程,那么只标记C语言标记。使用递归迭代链表有什么意义?请提供一个你没有删除的链接,因为行ifhead->next==NULL返回head;在这里使用递归是完全错误的。1.效率较低。2如果你的链表很长,你会遇到麻烦。3.迭代版本更容易编写。扔掉函数并正确地重写它,而不使用递归。