【问题标题】:Function delete all nodes of a given value in a linked list函数删除链表中给定值的所有节点
【发布时间】:2025-12-09 20:40:01
【问题描述】:

Funktion(deleteall) 获取一个链表和一个值,并删除所有持有该值的节点,然后在更改后返回该链表。

 Pointer deleteall(Pointer l, int v)
{
  
  Pointer temp;

  while(l != NULL)
  {
    if(l->val == v) {
      temp = l;
      l = temp ->next;
      free(temp);
      
    }
    if(l == NULL) return l;
    else l = l->next;
  }
  return l;
}

没有错误显示,编译完成,没有任何显示,我认为程序进入了无限循环。

【问题讨论】:

  • return l; 但你修改了l。在开头记住l,然后返回。
  • 当你free一个节点时,你还需要“填补”空白,即将前一个节点链接到下一个节点
  • 逻辑很奇怪。 “如果这个节点有正确的值,那么无论如何都跳过下一个?”可能不是你想要做的。
  • 这类问题非常适合调试器。尝试使用gdb,它将允许您逐行执行此函数,因此您可以查看行为错误的地方
  • 请试试这个*.com/questions/59097696/… 它应该可以帮助您查看 cmets 中提到的所有问题。我很想建议将其作为副本...

标签: c linked-list singly-linked-list pass-by-value function-definition


【解决方案1】:

这是一个相当短的实现。它使用了一个prev 指针,它指向前一个指针,指向一个当前元素。这样我们可以很容易地检查当前元素是否存在(列表没有用完),并且如果当前元素被删除并且下一个替换它,则沿着列表前进或保持当前位置。

Pointer deleteall(Pointer l, int v)
{
    Pointer* prev = &l;

    while (*prev != NULL)        // any items after the previous one?
    {
        Pointer curr = *prev;    // yes - so this is our current item
        if (curr->val == v)
        {
            *prev = curr->next;  // link next item to prev
            free(curr);
        }
        else
            prev = & curr->next; // step forward on the list
    }
    return l;                    // a new head of the list
}

【讨论】:

    【解决方案2】:

    你的函数总是返回一个空指针。

    当指向头节点的指针没有像函数定义中那样通过引用传递给函数时,函数必须返回指向头节点的指针。

    它可以如下所示

    Pointer deleteall(Pointer l, int v)
    {
        while ( l && l->val == v )
        {
            Pointer temp = l;
            l = l->next;
            free( temp );
        }
    
        if ( l )
        {
            for ( Pointer current = l; current->next != NULL; )
            {
                if ( current->next->val == v )
                {
                    Pointer temp = current->next;
                    current->next = current->next->next;
                    free( temp );
                }
                else
                {
                    current = current->next;
                }
            }
        }
    
        return l;
    }
    

    如果在main中指向头节点的指针也被命名为l,那么函数应该被称为

    l = deleteall( l, v );
    

    当指向头节点的指针通过引用传递时,可以查看更简单的函数定义。例如

    void deleteall(Pointer *l, int v)
    {
        while ( *l != NULL )
        {
            if ( ( *l )->val == v )
            {
                Pointer temp = *l;
                *l = ( *l )->next;
                free( temp );
            }
            else
            {
                l = &( *l )->next;
            }
        }
    }
    

    并且在 main 中可以像这样调用函数

    deleteall( &l, v );
    

    【讨论】:

      【解决方案3】:
      1. 您不需要返回指针。您只需要将列表的头部作为参数传递。然后创建一个临时指针,该指针初始化为 head 指向的位置,然后您可以从该位置开始工作
      2. 当您找到一个需要删除 val 的节点时,请确保您连接了要释放的节点的前一个节点和下一个节点。因此,链表保持链接状态

      在此我提出一个示例解决方案,假设列表 a) 头部与需要释放的头部不同,并且 b) 最后一个节点指向 NULL。我们保留 2 个临时指针,指向 a)Node 和 b)Node->next。我们总是检查Node->next,如果是one-to-be-released,我们连接没有它的list,然后释放它。

      void deleteall(Pointer l, int v)
      {
        
        Pointer temp, temp2;
        temp2 = l;
        temp = temp2->next;
      
        while(temp != NULL)
        {
          if(temp->val == v) {
            temp2->next = temp->next;
            free(temp);
            temp = temp2->next
      
          } else
          {
            temp2 = temp;
            temp = temp->next;
          if(temp == NULL)
            break;
      
        return;} 
      

      这个解决方案可以优化,但它对我个人有帮助,尤其是当我用指针和节点绘制图表时。

      【讨论】:

      • 你的函数可以调用未定义的行为。
      • @VladfromMoscow,请继续纠正我的细节,不客气:)
      • '你不需要返回一个指针。'根据所需的接口,函数可能会被赋予一个'head'指针并要求返回一个'head'指针(如果第一项被删除,可能会有所不同)。
      • 这个方案也可以通过一致的缩进来美化。