删除链表 C++ 中的特定节点

Posted

技术标签:

【中文标题】删除链表 C++ 中的特定节点【英文标题】:Deleting a specific node in Linked List C++ 【发布时间】:2021-07-22 15:33:38 【问题描述】:

我有一个保存学生数据的学生类,然后我的节点由这个学生类的一个对象组成。

我想删除分数低于 550 的学生。我的学生名单很长,但程序会在找出第一个分数低于 550 的人后删除所有数据。

这是我的链接列表:

class LinkList // Linked List 

    struct Node // structure for Node containing Object of Student class
    
        Student info;
        Node* link;
    ;
    Node* head;
    
public:
    
    LinkList() // default constructor
    
        head = NULL;
    
    
    void CreateEntry();
    void print();
    void Delete();

;

这是我的数据示例:(一行是每个节点)

S#  Roll_no     Name         marks
1   0777    Sherlock Holmes  777       
2   0789    John Watson      734       
3   0860    James moriarty   390       
4   0884    Irene Adler      732      
5   1003    Mycroft Holmes   410 
6   1004    Lord Blackwood   632      

这是我的删除功能:

Node* ptr = head;
    int n;
    
    while(ptr->link != NULL) // traversing to last element
    
        n = ptr->info.GetSerialNo(); // where n becomes the total number of elements
        ptr = ptr->link;
    

    Node* temp = head;
    for(int i=0; i<n; i++)
    
        if(temp->info.Getmarks() < 550) // Getmarks returns the marks
        
            if(temp != NULL && temp->link != NULL)
            
                Node* nodeToDelete = temp->link;
                temp->link = temp->link->link;
                delete nodeToDelete;
               
        
        else
        
            temp = temp->link;
        
    

我得到的输出是:

S#  Roll_no     Name         marks
1   0777    Sherlock Holmes  777       
2   0789    John Watson      734

【问题讨论】:

在调试器下运行你的程序,在Node* nodeToDelete = temp-&gt;link;所在的行设置一个断点。记下temp 变量的内容。现在一步一步直到你到达下一次迭代的开始。 temp 现在的价值是多少?发生什么了?更重要的是,您预计会发生什么,为什么没有呢? 无关:如果列表为空,while(ptr-&gt;link != NULL) 会死得很惨,因为ptr 将是NULL。修复它,您会发现该功能仅在您第一次删除节点时才能正常工作。之后,序列号可能无法准确表示列表中的节点数。也就是说,为什么不在那个初始循环中进行搜索和删除?搜索直到列表中没有更多节点。这将永远有效。 不相关:您的 temp != NULL 检查没有用(您已经访问了上面的 temp )并且您的编译器可能删除了检查。如果您的警告级别足够高,它应该会警告您。 无关:您将序列号分配给n 以获取列表的长度,但您允许删除。这可能意味着您的最终n 大于或小于列表的长度。为什么还要使用n?您可以将 for 循环重写为 for(Node *ptr = head; ptr != NULL; ptr = ptr -&gt; link),它会为您完成所有检查 完全无关:Sherlock 到底是怎么比他的哥哥更聪明的? 【参考方案1】:

我想删除分数低于 550 的学生

您的Delete() 比完成该任务所需的复杂得多。而且,它也有一些逻辑错误。

试试类似的方法:

void LinkList::Delete()

    Node* ptr = head;
    Node* previous = NULL;
    
    while (ptr != NULL)
    
        Node* nextNode = ptr->link;

        if (ptr->info.Getmarks() < 550)
        
            if (previous)
                previous->link = nextNode;

            if (head == ptr)
                head = nextNode;

            delete ptr;
        
        else
            previous = ptr;

        ptr = nextNode;
    

或者:

void LinkList::Delete()

    Node* ptr = head;
    Node** previous = &head;
    
    while (ptr != NULL)
    
        Node* nextNode = ptr->link;

        if (ptr->info.Getmarks() < 550)
        
            *previous = nextNode;
            delete ptr;
        
        else
            previous = &(ptr->next);

        ptr = nextNode;
    


话虽如此,你真的应该使用标准的std::list容器而不是自己制作链表,那么你可以这样做:

#include <list>

class LinkList // Linked List 

    std::list<Student> students;
    
public:
    
    LinkList() = default; // default constructor
    
    ...
    void Delete();

;
#include <algorithm>

void LinkList::Delete()

    students.erase(
        std::remove_if(students.begin(), students.end(),
            [](Student &s) return s.Getmarks() < 550; 
        ),
        students.end()
    );

【讨论】:

以上是关于删除链表 C++ 中的特定节点的主要内容,如果未能解决你的问题,请参考以下文章

从链表 C++ 中删除节点

237. 删除链表中的节点

题目地址(237. 删除链表中的节点)

C++链表不删除头节点

如何“完全”删除链表中的所有节点?

算法系列——删除链表中的节点