从列表末尾删除时,LinkedList Remove 函数失败 C++

问题描述

我有一个 LinkedList 类,除了我的删除功能外,一切正常。除了从末尾移除时,它可以工作。如果我从最后删除然后尝试显示新列表,程序会崩溃并且不会给我错误。我想知道是否有人可以帮助我查明我在移除尾部的 remove 函数中做错了什么。

主要方法

#include "LinkedList.h"
#include <cstdlib>
#include <iomanip>

using namespace std;

void MainMenu(int& menu);

int main(int argc,char** argv) {
    int menu = 0;
    string name;
    LinkedList list;
    while (true)
    {
        
        MainMenu(menu);
        if (menu == 1)
        {
            cout << "Please enter the name you want to add to the front: " << endl;
            cin >> name;
            list.addFront(name);
        }
        else if (menu == 2)
        {
            cout << "Please enter the name you want to add to the back: " << endl;
            cin >> name;
            list.addBack(name);
        }
        else if (menu == 3)
        {
            cout << "Please enter the name you want to remove: " << endl;
            cin >> name;
            list.remove(name);
        }
        else if (menu == 4)
        {
            list.display();
        }
        else if (menu == 5)
        {
            cout << "\nThank you for using my program!" << endl;
            exit(0);
        }
    }

    return 0;
}
void MainMenu(int& menu)
{
    cout << '\n' << endl;
    cout << left << setw(30) << right << setw(20) << "Main Menu" << endl;
    cout << setw(36) << setfill('*') << "\n" << endl;
    cout << "1. Add node to front." << endl;
    cout << "2. Add node to back." << endl;
    cout << "3. Remove node." << endl;
    cout << "4. display list." << endl;
    cout << "5. Exit" << endl;
    cout << setw(36) << "\n" << endl;
    cout << "Please enter a menu number to proceed: " << endl;
    cin >> menu;
    while (menu != 1 && menu != 2 && menu != 3 && menu != 4 && menu != 5)
    {
        cout << "Menu options are 1 - 5" << endl;
        cout << "Please enter a menu number to proceed: " << endl;
        cin.clear();
        cin.ignore(100,'\n');
        cin >> menu;
    }
    cout << setfill(' ') << "\n" << endl;
}

文件


#include <iostream>

using namespace std;

#ifndef LINKEDLIST_H
#define LINKEDLIST_H
struct Node
{
    string name;
    Node * next;
};

class LinkedList {
public:
    Node * head = nullptr;
    Node * tail = nullptr;
    Node * current = nullptr;
    void addFront(string name);
    void addBack(string name);
    void remove(string name);
    void display();
    LinkedList();
    LinkedList(const LinkedList& orig);
    virtual ~LinkedList();
private:

};

#endif /* LINKEDLIST_H */

文件

#include "LinkedList.h"

void LinkedList::addFront(string name)
{
    Node * node = new Node();
    node->name = name;
    if (head != nullptr)
    {
        node->next = head;
        head = node;
    }
    else
    {
        head = node;
        tail = node;
    }
}
void LinkedList::addBack(string name)
{
    Node * node = new Node();
    node->name = name;
    node->next = nullptr;
    if (head == nullptr)
    {
        head = node;
        tail = node;
    }
    else
    {
      
        node->next = nullptr;
        tail->next = node;
        tail = node;
    }
}

void LinkedList::remove(string name)
{
    Node * temp = head;
    while (temp != nullptr)
    {
        if (temp->name == name)
        {
            cout << "Name found! Being removed." << endl;
            break;
        }
        temp = temp->next;
        if (temp == nullptr)
        {
            cout << "Name not found!" << endl;
            return;
        }
    } 
    temp = head;
    if(head == nullptr)
    {
        cout << "The list is empty." << endl;
        return;
    }
    while(!(temp->name == name))
    {
        temp = temp->next;
    }
    if (temp == tail && temp == head)
    {
        head = nullptr;
        tail = nullptr;
        delete temp;
    }
    else if (temp == tail)
    {
        temp->next = tail;
        delete temp->next;
        temp->next = nullptr;
        tail = temp;
    }
    else if(temp == head)
    {
        temp = head;
        head = temp->next;
 
        delete temp;
    }
    else
    {
        temp = head;
        while(!(temp->next->name == name))
        {
            temp = temp->next;
        }
        Node * next = temp->next->next;
        delete temp->next;
        temp->next = next;  
        
    }
    
}
void LinkedList::display()
{
    current = head;
    if (current == nullptr)
    {
        cout << "The list is empty!" << endl;
    }
    while (current != nullptr)
    {
        cout << current->name << endl;
        current = current->next;
    }
}
LinkedList::LinkedList() {
}

LinkedList::LinkedList(const LinkedList& orig) {
}

LinkedList::~LinkedList() {
}

解决方法

您的主要问题是这里的这一部分

else if (temp == tail)
    {
        temp->next = tail;
        delete temp->next;
        temp->next = nullptr;
        tail = temp;
    }

如果匹配项是最后一项,这就是执行的操作。但是如果它是最后一项,那么 temp->next 将是 tail,因为您只是将它设置为尾部,并且因为 temp == tail 也使 temp 无效。设置 temp->next 将使用已删除的指针。目前没有解决这个问题,因为您需要将前一个节点设置为 tail,而您没有保存它,因此您必须再次循环才能获取它。

现在,对于解决方案,您应该执行一个循环。无需多次循环(大多数情况下为 3)

void LinkedList::remove(string name)
{
    Node * temp = head;
    Node * prev = nullptr;
    while (temp != nullptr)
    {
        if (temp->name == name)
        {
            cout << "Name found! Being removed." << endl;
            if (prev != nullptr) {
                prev->next = temp->next
            }
            else {
                head = temp->next;
            }
            if (tail == temp) {
                tail = prev;
            }
            delete temp;
            return;
        }
        prev = temp;
        temp = temp->next;
    } 
    cout << "Name not found!" << endl;
}
,

对于成员函数声明中的任何地方的初学者来说,其中的参数声明为

string name

你应该把它改成

const string &name

其次,成员函数remove不应发出任何消息。决定是否输出消息的是函数的调用者。

您的函数效率低下,因为它在循环中遍历列表两甚至三次,并且条件太多,使函数过于复杂。因此该函数存在错误。

例如在这个 if 语句中

else if (temp == tail)
{
    temp->next = tail;
    delete temp->next;
    temp->next = nullptr;
    tail = temp;
}

使用删除指针temp来访问内存,因为temp等于tail(根据if语句的条件)

    temp->next = nullptr;

并再次将tail设置为已删除的指针

    tail = temp;

可以通过以下方式声明和定义函数

class LinkedList {
public:
    //...
    bool remove( const std::string &name );
};

bool LinkedList::remove( const std::string &name )
{
    Node *prev = nullptr;
    Node *current = head;
    
    while ( current && current->name != name )
    {
        prev = current;
        current = current->next;
    }
    
    bool success = current != nullptr;
    
    if ( success )
    {
        if ( prev )
        {
            prev->next = current->next;
            if ( prev->next == nullptr ) tail = prev;
        }
        else
        {
            head = head->next;
            if ( head == nullptr ) tail = nullptr;
        }
        
        delete current;
    }
    
    return success;
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...