如何删除双向链表中与特定值匹配的所有项目

How to delete all items in a doubly linked list that match a certain value?

本文关键字:项目 何删除 删除 双向链表      更新时间:2023-10-16

我有一个作业,我必须编写一个函数,该函数可以删除双链表的任何部分,该双向链表有一个具有预定输入的值。我为此工作了相当长一段时间,我找不到我编写的代码的任何其他错误。作业内容如下:

编写一个C++函数来删除链表中的节点。该函数采用两个参数 - 链表的头部和要删除的值。它应该删除包含要删除的值的所有节点。它应该返回链表的头部。

链表结构:

struct node
{
    int value;
    node *next;
    node *prev;
};
node *DeleteNode(node *head, int value){
node *tmp=head;
while(tmp!=NULL){
    if(tmp->value==value){
        if(tmp==head){
            head=head->next;
            head->prev=NULL;
            delete tmp;
            tmp=head;
        }
        else if(tmp->next==NULL){
            node *temp=tmp;
            temp->prev->next=NULL;
            delete tmp;
            tmp=temp;
        }
        else{
            node *node1=tmp;
            node1->prev->next=node1->next;
            node1->next->prev=node1->prev;
            delete tmp;
            tmp=node1;
        }
    }
    tmp=tmp->next;
}
return head;}

因此,当它运行测试时

1 <-> 2 <-> 3 <-> 4

并且需要删除所有 3,它得到的结果是

1 <-> 2 <-> 4

这是正确的。它适用于需要删除头部项目的其他示例,以及需要删除尾部的示例。它与每个所需的功能一起工作。此外。。。

2 <-> 2 <-> 2 <-> 2 <-> 65 <-> 83

需要删除 2 的地方。它只得到一个结果

2<-> 65 <-> 83

因此,由于某种原因,还剩下额外的 2 个。有什么猜测吗?我已经为这个问题提供了我提供的一切。我认为问题可能出在我的部分删除双向链表中的中间项目,但我完全迷失了。非常感谢!

这看起来很可疑(添加一些空格):

node* node1 = tmp;
node1->prev->next = node1->next;
node1->next->prev = node1->prev;
delete tmp;
tmp = node1;

node1只是tmp的别名。它实际上没有任何其他目的。然后你delete tmp并将其分配给node1 - 这正是你刚刚删除的内容!

您可能想执行以下操作:

tmp->prev->next = tmp->next;
tmp->next->prev = tmp->prev;
node* prev = tmp->prev;
delete tmp;
tmp = prev; 

当初始头节点与值匹配时,会出现此问题。

在这种情况下,您将下一个节点设置为新头并摆脱旧头,然后将 tmp 设置为新头,

if(tmp==head){
        head=head->next;
        head->prev=NULL;
        delete tmp;
        tmp=head;
 }

然后当你退出你设置的 if 语句时

tmp = tmp-> next
因此,在 if 块中,您将当前节点设置为下一个节点,然后

删除曾经是当前节点的内容,然后当您退出 if 语句时,您将再次向下移动到下一个节点,有效地完全跳过新的头节点。

我补充了巴里的回答:

node *temp=tmp;
temp->prev->next=NULL;
delete tmp;
tmp=temp;

这将为当前节点tmp设置别名temp,然后将上一个节点的next指针设置为 NULL,删除当前节点并将 tmp 指针设置为 temp ,但这只是刚刚删除的节点的别名。您可能希望node *temp=tmp->prev;将 tmp 设置为新的最后一个元素。

可能导致您的错误的是,关于您与价值的比较,您调用

tmp=tmp->next;

最后,转到下一个节点。您应该将其包装在 else 块中,以便仅在您的值不匹配时才执行。

定义双向链表时,通常会定义一个单独的结构,其中包含两个指针:一个指向列表头部的指针,另一个指向列表尾部的指针。例如

struct list
{
    node *head = nullptr;
    node *tail = nullptr;
    //...
};

同样在结构内部声明成员函数处理列表。

但是,如果使用您的方法,那么删除所有值等于给定值的节点的函数可以看起来像本演示程序中显示的那样

#include <iostream>
struct node
{
    int value;
    node *next;
    node *prev;
};
void display( node *head )
{
    for ( ; head; head = head->next )
    {
        std::cout << head->value << ' ';
    }
    std::cout << std::endl;
}
node * AppendNode( node *head, int value )
{
    node *tmp = new node { value, nullptr, nullptr };
    if ( !head )
    {
        head = tmp;
    }
    else
    {
        node *prev = head;
        while ( prev->next ) prev = prev->next;
        tmp->prev = prev;
        prev->next = tmp;
    }
    return head;
}
node * DeleteNode( node *head, int value )
{
    for ( node *current = head; current; )
    {
        if ( current->value == value )
        {
            node *tmp = current;
            if ( current->next )
            {
                current->next->prev = current->prev;
            }
            if ( current->prev )
            {
                current->prev->next = current->next;
                current = current->next;
            }
            else
            {
                head = current->next;
                current = head;
            }
            delete tmp;
        }
        else
        {
            current = current->next;
        }            
    }
    return head;
}    
int main()
{
    node *head = nullptr;
    for ( int x : { 2, 2, 2, 2, 65, 83 } ) head = AppendNode( head, x );
    display( head );
    head = DeleteNode( head, 2 );
    display( head );
    head = DeleteNode( head, 83 );
    display( head );
    head = DeleteNode( head, 65 );
    display( head );
}

它的输出是

2 2 2 2 65 83 
65 83 
65