问题描述
我有一个 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;
}