单向链表删除头节点后指向垃圾值的头指针
Head pointer pointing to garbage value after deleting node from head in singly linked list
我正在尝试用 C++ 实现单向链表。 delete temp;
语句之前的 deleteFromHead()
一切正常。在语句之后,head
和 next
都开始指向一些垃圾值。由于这是从头部删除节点的标准方法,所以我无法找出问题所在。
这是完整的代码:
#include <iostream>
#include <iomanip>
#include <limits>
#define CLEAR_INPUT_BUFFER(c) \
c.clear(); \
c.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
template <class T>
class SLLNode {
public:
T data;
SLLNode<T>* next;
SLLNode(void) {
data = static_cast<T>(0);
next = NULL;
}
SLLNode(T data) {
this -> data = data;
next = NULL;
}
~SLLNode(void) {
delete next;
}
};
template <class T>
class SLList {
private:
SLLNode<T>* head;
SLLNode<T>* tail;
public:
SLList(void) {
head = tail = NULL;
}
~SLList(void) {
delete head;
delete tail;
}
int addAtHead(T data) {
SLLNode<T>* temp;
if(!(temp = new SLLNode<T>(data))) {
return -1;
}
if(head == NULL && tail == NULL) {
head = temp;
tail = temp;
} else {
temp -> next = head;
head = temp;
}
return 0;
}
int addAtTail(T data) {
SLLNode<T>* temp;
if(!(temp = new SLLNode<T>(data))) {
return -1;
}
if(head == NULL && tail == NULL) {
head = temp;
tail = temp;
} else {
tail -> next = temp;
tail = temp;
}
return 0;
}
int deleteFromHead(void) {
if(head == NULL && tail == NULL) {
return -1;
} else if(head == tail) {
delete head;
head = NULL;
tail = NULL;
} else {
std::cout << "\nhere\n";
SLLNode<T>* temp = head;
std::cout << "temp -> data = " << temp -> data;
std::cout << "\nhead -> data = " << head -> data;
std::cout << "\n\nhead -> next -> data = " << head -> next -> data;
std::cout << "\ntemp -> next -> data = " << temp -> next -> data;
head = head -> next;
std::cout << "\n\nafter head = head -> next:";
std::cout << "\nhead -> data = " << head -> data;
std::cout << "\ntemp -> data = " << temp -> data;
delete temp;
std::cout << "\n\nafter delete temp:";
std::cout << "\nhead -> data = " << head -> data;
std::cout << "\ntemp -> data = " << temp -> data;
}
return 0;
}
int deleteFromTail(void) {
if(head == NULL && tail == NULL) {
return -1;
} else if(head == tail) {
delete tail;
head = NULL;
tail = NULL;
} else {
SLLNode<T>* temp = head;
while(temp -> next -> next != NULL) {
temp = temp -> next;
}
temp -> next = NULL;
delete tail;
tail = temp;
}
return 0;
}
void traverse(void) {
if(head == NULL && tail == NULL) {
std::cout << "\nNo node present in the linked list.";
return;
} else {
SLLNode<T>* temp = head;
std::cout << "\ntemp -> data = " << temp -> data << std::endl;
while(temp != NULL) {
std::cout << temp -> data << " ";
temp = temp -> next;
}
}
return;
}
int search(T data) {
if(head == NULL && tail == NULL) {
return -2;
} else {
int index = 1;
SLLNode<T>* temp = head;
while(temp != NULL) {
if(temp -> data == data) {
return index;
} else {
++index;
temp = temp -> next;
}
}
}
return -1;
}
};
int main(void) {
int choice;
SLList<int> sll;
while(true) {
std::cout << "\t\tSINGLY LINKED LIST DEMO PROGRAM\n\n\t\t"
<< "----------MENU----------\n\t\t"
<< "1. Add at head\n\t\t"
<< "2. Add at tail\n\t\t"
<< "3. Delete from head\n\t\t"
<< "4. Delete from tail\n\t\t"
<< "5. Traverse the list\n\t\t"
<< "6. Search the list\n\t\t"
<< "7. Exit the program\n\n"
<< "Enter your choice: ";
while(!(std::cin >> choice) || !(choice >= 1 && choice <= 7)) {
std::cout << "Please enter a valid choice: ";
CLEAR_INPUT_BUFFER(std::cin);
}
CLEAR_INPUT_BUFFER(std::cin);
switch(choice) {
case 1 : {
int data;
std::cout << "Enter the data (any number): ";
while(!(std::cin >> data)) {
std::cout << "Please enter a valid number: ";
CLEAR_INPUT_BUFFER(std::cin);
}
CLEAR_INPUT_BUFFER(std::cin);
if(sll.addAtHead(data) == -1) {
std::cerr << "\nERROR: Memory could not be allocated\n";
exit(-1);
}
}
break;
case 2 : {
int data;
std::cout << "Enter the data (any number): ";
while(!(std::cin >> data)) {
std::cout << "Please enter a valid number: ";
CLEAR_INPUT_BUFFER(std::cin);
}
CLEAR_INPUT_BUFFER(std::cin);
if(sll.addAtTail(data) == -1) {
std::cerr << "\nERROR: Memory could not be allocated\n";
exit(-1);
}
}
break;
case 3 : {
if(sll.deleteFromHead() == -1) {
std::cout << "\nLinked list is empty!";
}
}
break;
case 4 : {
if(sll.deleteFromTail() == -1) {
std::cout << "\nLinked list is empty!";
}
}
break;
case 5 : {
std::cout << "\nLinked List:\n";
sll.traverse();
}
break;
case 6 : {
int data, index;
std::cout << "Enter the data to be searched (any number) : ";
while(!(std::cin >> data)) {
std::cout << "Please enter a valid number: ";
CLEAR_INPUT_BUFFER(std::cin);
}
CLEAR_INPUT_BUFFER(std::cin);
index = sll.search(data);
if(index == -1) {
std::cout << "\nValue not found.\n";
} else if(index == -2) {
std::cout << "\nNo node is present in the linked list.\n";
} else {
std::cout << "\nValue found at node number: " << index;
}
}
break;
case 7 : {
// code
}
break;
}
}
return 0;
}
链表为:68 -> 59 -> 32 -> 74 -> 86
输出为:
请帮忙。
您确实应该使用标准的 std::list
(双链接)或 std::forward_list
(单链接)容器,而不是手动实现链接列表。特别是因为您的实现中存在逻辑错误。
也就是说,SLLNode
class 的递归析构函数是一个 非常糟糕的主意 ,您需要摆脱它。它可能导致大型列表的堆栈溢出。但更重要的是,它是您垃圾问题的根本原因。它正在删除您之后尝试访问的节点。
具体
在你的 SLList
析构函数中,调用 delete head
释放整个节点列表,在调用 delete tail
之前使 tail
指针无效(这你根本不应该打电话)。
在您的 deleteFromHead()
方法中,您在更新 head
指针之前持有指向原始 head
节点的 temp
指针,然后您在调用 delete temp
时没有先将 temp->next
重置为 NULL,因此 您正在清除整个节点列表 ,使 head
和 tail
指针.
切勿使用递归析构函数!释放列表中的下一个节点不应该是 SLLNode
的责任。当不再使用时,释放每个节点应该是 SLList
的责任。要清除整个节点列表,请 SLList
使用迭代循环而不是递归循环。
尝试更像这样的东西:
#include <iostream>
#include <iomanip>
#include <limits>
#include <new>
#define CLEAR_INPUT_BUFFER(c) \
c.clear(); \
c.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
template <class T>
class SLLNode {
public:
T data;
SLLNode<T>* next;
SLLNode() : data(), next(NULL) {}
SLLNode(const T &data) : data(data), next(NULL) {}
};
template <class T>
class SLList {
private:
SLLNode<T>* head;
SLLNode<T>* tail;
SLList(const SLList&) {}
SLList& operator=(const SLList&) {}
public:
SLList() : head(NULL), tail(NULL) {}
~SLList() {
clear();
}
void clear() {
SLLNode<T> *temp = head;
head = tail = NULL;
while (temp) {
SLLNode<T> *next = temp->next;
delete temp;
temp = next;
}
}
int addAtHead(const T &data) {
SLLNode<T>* temp = new(std::nothrow) SLLNode<T>(data);
if (!temp) {
return -1;
}
temp->next = head;
head = temp;
if (!tail) {
tail = temp;
}
return 0;
}
int addAtTail(const T &data) {
SLLNode<T>* temp = new(std::nothrow) SLLNode<T>(data);
if (!temp) {
return -1;
}
if (!head) {
head = temp;
}
if (tail) {
tail->next = temp;
}
tail = temp;
return 0;
}
int deleteFromHead() {
if (!head) {
return -1;
}
SLLNode<T>* temp = head;
if (head == tail) {
tail = NULL;
}
head = head->next;
delete temp;
return 0;
}
int deleteFromTail() {
if (!head) {
return -1;
}
SLLNode<T>* temp = head, *newTail = NULL;
while (temp->next) {
newTail = temp;
temp = temp->next;
}
if (newTail) {
newTail->next = NULL;
}
if (head == tail) {
head = NULL;
}
tail = newTail;
delete temp;
return 0;
}
void traverse() {
if (!head) {
std::cout << "\nNo node present in the linked list." << std::endl;
return;
}
SLLNode<T>* temp = head;
std::cout << "\n" << temp->data;
while (temp->next) {
temp = temp->next;
std::cout << " " << temp->data;
}
std::cout << std::endl;
}
int search(const T &data) {
if (!head) {
return -2;
}
int index = 0;
SLLNode<T>* temp = head;
do {
if (temp->data == data) {
return index;
}
++index;
temp = temp->next;
}
while (temp);
return -1;
}
};
int main() {
int choice;
SLList<int> sll;
do {
std::cout << "\t\tSINGLY LINKED LIST DEMO PROGRAM\n\n\t\t"
<< "----------MENU----------\n\t\t"
<< "1. Add at head\n\t\t"
<< "2. Add at tail\n\t\t"
<< "3. Delete from head\n\t\t"
<< "4. Delete from tail\n\t\t"
<< "5. Traverse the list\n\t\t"
<< "6. Search the list\n\t\t"
<< "7. Exit the program\n\n"
<< "Enter your choice: ";
while (!(std::cin >> choice) || !(choice >= 1 && choice <= 7)) {
std::cout << "Please enter a valid choice: ";
CLEAR_INPUT_BUFFER(std::cin);
}
switch (choice) {
case 1 : {
int data;
std::cout << "Enter the data (any number): ";
while (!(std::cin >> data)) {
std::cout << "Please enter a valid number: ";
CLEAR_INPUT_BUFFER(std::cin);
}
if (sll.addAtHead(data) == -1) {
std::cerr << "\nERROR: Memory could not be allocated\n";
return -1;
}
}
break;
case 2 : {
int data;
std::cout << "Enter the data (any number): ";
while (!(std::cin >> data)) {
std::cout << "Please enter a valid number: ";
CLEAR_INPUT_BUFFER(std::cin);
}
if (sll.addAtTail(data) == -1) {
std::cerr << "\nERROR: Memory could not be allocated\n";
return -1;
}
}
break;
case 3 : {
if (sll.deleteFromHead() == -1) {
std::cout << "\nLinked list is empty!";
}
}
break;
case 4 : {
if (sll.deleteFromTail() == -1) {
std::cout << "\nLinked list is empty!";
}
}
break;
case 5 : {
std::cout << "\nLinked List:\n";
sll.traverse();
}
break;
case 6 : {
int data, index;
std::cout << "Enter the data to be searched (any number) : ";
while (!(std::cin >> data)) {
std::cout << "Please enter a valid number: ";
CLEAR_INPUT_BUFFER(std::cin);
}
index = sll.search(data);
if (index == -2) {
std::cout << "\nNo node is present in the linked list.\n";
}
else if (index == -1) {
std::cout << "\nValue not found.\n";
}
else {
std::cout << "\nValue found at node number: " << index;
}
}
break;
}
}
while (choice != 7);
return 0;
}
我正在尝试用 C++ 实现单向链表。 delete temp;
语句之前的 deleteFromHead()
一切正常。在语句之后,head
和 next
都开始指向一些垃圾值。由于这是从头部删除节点的标准方法,所以我无法找出问题所在。
这是完整的代码:
#include <iostream>
#include <iomanip>
#include <limits>
#define CLEAR_INPUT_BUFFER(c) \
c.clear(); \
c.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
template <class T>
class SLLNode {
public:
T data;
SLLNode<T>* next;
SLLNode(void) {
data = static_cast<T>(0);
next = NULL;
}
SLLNode(T data) {
this -> data = data;
next = NULL;
}
~SLLNode(void) {
delete next;
}
};
template <class T>
class SLList {
private:
SLLNode<T>* head;
SLLNode<T>* tail;
public:
SLList(void) {
head = tail = NULL;
}
~SLList(void) {
delete head;
delete tail;
}
int addAtHead(T data) {
SLLNode<T>* temp;
if(!(temp = new SLLNode<T>(data))) {
return -1;
}
if(head == NULL && tail == NULL) {
head = temp;
tail = temp;
} else {
temp -> next = head;
head = temp;
}
return 0;
}
int addAtTail(T data) {
SLLNode<T>* temp;
if(!(temp = new SLLNode<T>(data))) {
return -1;
}
if(head == NULL && tail == NULL) {
head = temp;
tail = temp;
} else {
tail -> next = temp;
tail = temp;
}
return 0;
}
int deleteFromHead(void) {
if(head == NULL && tail == NULL) {
return -1;
} else if(head == tail) {
delete head;
head = NULL;
tail = NULL;
} else {
std::cout << "\nhere\n";
SLLNode<T>* temp = head;
std::cout << "temp -> data = " << temp -> data;
std::cout << "\nhead -> data = " << head -> data;
std::cout << "\n\nhead -> next -> data = " << head -> next -> data;
std::cout << "\ntemp -> next -> data = " << temp -> next -> data;
head = head -> next;
std::cout << "\n\nafter head = head -> next:";
std::cout << "\nhead -> data = " << head -> data;
std::cout << "\ntemp -> data = " << temp -> data;
delete temp;
std::cout << "\n\nafter delete temp:";
std::cout << "\nhead -> data = " << head -> data;
std::cout << "\ntemp -> data = " << temp -> data;
}
return 0;
}
int deleteFromTail(void) {
if(head == NULL && tail == NULL) {
return -1;
} else if(head == tail) {
delete tail;
head = NULL;
tail = NULL;
} else {
SLLNode<T>* temp = head;
while(temp -> next -> next != NULL) {
temp = temp -> next;
}
temp -> next = NULL;
delete tail;
tail = temp;
}
return 0;
}
void traverse(void) {
if(head == NULL && tail == NULL) {
std::cout << "\nNo node present in the linked list.";
return;
} else {
SLLNode<T>* temp = head;
std::cout << "\ntemp -> data = " << temp -> data << std::endl;
while(temp != NULL) {
std::cout << temp -> data << " ";
temp = temp -> next;
}
}
return;
}
int search(T data) {
if(head == NULL && tail == NULL) {
return -2;
} else {
int index = 1;
SLLNode<T>* temp = head;
while(temp != NULL) {
if(temp -> data == data) {
return index;
} else {
++index;
temp = temp -> next;
}
}
}
return -1;
}
};
int main(void) {
int choice;
SLList<int> sll;
while(true) {
std::cout << "\t\tSINGLY LINKED LIST DEMO PROGRAM\n\n\t\t"
<< "----------MENU----------\n\t\t"
<< "1. Add at head\n\t\t"
<< "2. Add at tail\n\t\t"
<< "3. Delete from head\n\t\t"
<< "4. Delete from tail\n\t\t"
<< "5. Traverse the list\n\t\t"
<< "6. Search the list\n\t\t"
<< "7. Exit the program\n\n"
<< "Enter your choice: ";
while(!(std::cin >> choice) || !(choice >= 1 && choice <= 7)) {
std::cout << "Please enter a valid choice: ";
CLEAR_INPUT_BUFFER(std::cin);
}
CLEAR_INPUT_BUFFER(std::cin);
switch(choice) {
case 1 : {
int data;
std::cout << "Enter the data (any number): ";
while(!(std::cin >> data)) {
std::cout << "Please enter a valid number: ";
CLEAR_INPUT_BUFFER(std::cin);
}
CLEAR_INPUT_BUFFER(std::cin);
if(sll.addAtHead(data) == -1) {
std::cerr << "\nERROR: Memory could not be allocated\n";
exit(-1);
}
}
break;
case 2 : {
int data;
std::cout << "Enter the data (any number): ";
while(!(std::cin >> data)) {
std::cout << "Please enter a valid number: ";
CLEAR_INPUT_BUFFER(std::cin);
}
CLEAR_INPUT_BUFFER(std::cin);
if(sll.addAtTail(data) == -1) {
std::cerr << "\nERROR: Memory could not be allocated\n";
exit(-1);
}
}
break;
case 3 : {
if(sll.deleteFromHead() == -1) {
std::cout << "\nLinked list is empty!";
}
}
break;
case 4 : {
if(sll.deleteFromTail() == -1) {
std::cout << "\nLinked list is empty!";
}
}
break;
case 5 : {
std::cout << "\nLinked List:\n";
sll.traverse();
}
break;
case 6 : {
int data, index;
std::cout << "Enter the data to be searched (any number) : ";
while(!(std::cin >> data)) {
std::cout << "Please enter a valid number: ";
CLEAR_INPUT_BUFFER(std::cin);
}
CLEAR_INPUT_BUFFER(std::cin);
index = sll.search(data);
if(index == -1) {
std::cout << "\nValue not found.\n";
} else if(index == -2) {
std::cout << "\nNo node is present in the linked list.\n";
} else {
std::cout << "\nValue found at node number: " << index;
}
}
break;
case 7 : {
// code
}
break;
}
}
return 0;
}
链表为:68 -> 59 -> 32 -> 74 -> 86
输出为:
您确实应该使用标准的 std::list
(双链接)或 std::forward_list
(单链接)容器,而不是手动实现链接列表。特别是因为您的实现中存在逻辑错误。
也就是说,SLLNode
class 的递归析构函数是一个 非常糟糕的主意 ,您需要摆脱它。它可能导致大型列表的堆栈溢出。但更重要的是,它是您垃圾问题的根本原因。它正在删除您之后尝试访问的节点。
具体
在你的
SLList
析构函数中,调用delete head
释放整个节点列表,在调用delete tail
之前使tail
指针无效(这你根本不应该打电话)。在您的
deleteFromHead()
方法中,您在更新head
指针之前持有指向原始head
节点的temp
指针,然后您在调用delete temp
时没有先将temp->next
重置为 NULL,因此 您正在清除整个节点列表 ,使head
和tail
指针.
切勿使用递归析构函数!释放列表中的下一个节点不应该是 SLLNode
的责任。当不再使用时,释放每个节点应该是 SLList
的责任。要清除整个节点列表,请 SLList
使用迭代循环而不是递归循环。
尝试更像这样的东西:
#include <iostream>
#include <iomanip>
#include <limits>
#include <new>
#define CLEAR_INPUT_BUFFER(c) \
c.clear(); \
c.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
template <class T>
class SLLNode {
public:
T data;
SLLNode<T>* next;
SLLNode() : data(), next(NULL) {}
SLLNode(const T &data) : data(data), next(NULL) {}
};
template <class T>
class SLList {
private:
SLLNode<T>* head;
SLLNode<T>* tail;
SLList(const SLList&) {}
SLList& operator=(const SLList&) {}
public:
SLList() : head(NULL), tail(NULL) {}
~SLList() {
clear();
}
void clear() {
SLLNode<T> *temp = head;
head = tail = NULL;
while (temp) {
SLLNode<T> *next = temp->next;
delete temp;
temp = next;
}
}
int addAtHead(const T &data) {
SLLNode<T>* temp = new(std::nothrow) SLLNode<T>(data);
if (!temp) {
return -1;
}
temp->next = head;
head = temp;
if (!tail) {
tail = temp;
}
return 0;
}
int addAtTail(const T &data) {
SLLNode<T>* temp = new(std::nothrow) SLLNode<T>(data);
if (!temp) {
return -1;
}
if (!head) {
head = temp;
}
if (tail) {
tail->next = temp;
}
tail = temp;
return 0;
}
int deleteFromHead() {
if (!head) {
return -1;
}
SLLNode<T>* temp = head;
if (head == tail) {
tail = NULL;
}
head = head->next;
delete temp;
return 0;
}
int deleteFromTail() {
if (!head) {
return -1;
}
SLLNode<T>* temp = head, *newTail = NULL;
while (temp->next) {
newTail = temp;
temp = temp->next;
}
if (newTail) {
newTail->next = NULL;
}
if (head == tail) {
head = NULL;
}
tail = newTail;
delete temp;
return 0;
}
void traverse() {
if (!head) {
std::cout << "\nNo node present in the linked list." << std::endl;
return;
}
SLLNode<T>* temp = head;
std::cout << "\n" << temp->data;
while (temp->next) {
temp = temp->next;
std::cout << " " << temp->data;
}
std::cout << std::endl;
}
int search(const T &data) {
if (!head) {
return -2;
}
int index = 0;
SLLNode<T>* temp = head;
do {
if (temp->data == data) {
return index;
}
++index;
temp = temp->next;
}
while (temp);
return -1;
}
};
int main() {
int choice;
SLList<int> sll;
do {
std::cout << "\t\tSINGLY LINKED LIST DEMO PROGRAM\n\n\t\t"
<< "----------MENU----------\n\t\t"
<< "1. Add at head\n\t\t"
<< "2. Add at tail\n\t\t"
<< "3. Delete from head\n\t\t"
<< "4. Delete from tail\n\t\t"
<< "5. Traverse the list\n\t\t"
<< "6. Search the list\n\t\t"
<< "7. Exit the program\n\n"
<< "Enter your choice: ";
while (!(std::cin >> choice) || !(choice >= 1 && choice <= 7)) {
std::cout << "Please enter a valid choice: ";
CLEAR_INPUT_BUFFER(std::cin);
}
switch (choice) {
case 1 : {
int data;
std::cout << "Enter the data (any number): ";
while (!(std::cin >> data)) {
std::cout << "Please enter a valid number: ";
CLEAR_INPUT_BUFFER(std::cin);
}
if (sll.addAtHead(data) == -1) {
std::cerr << "\nERROR: Memory could not be allocated\n";
return -1;
}
}
break;
case 2 : {
int data;
std::cout << "Enter the data (any number): ";
while (!(std::cin >> data)) {
std::cout << "Please enter a valid number: ";
CLEAR_INPUT_BUFFER(std::cin);
}
if (sll.addAtTail(data) == -1) {
std::cerr << "\nERROR: Memory could not be allocated\n";
return -1;
}
}
break;
case 3 : {
if (sll.deleteFromHead() == -1) {
std::cout << "\nLinked list is empty!";
}
}
break;
case 4 : {
if (sll.deleteFromTail() == -1) {
std::cout << "\nLinked list is empty!";
}
}
break;
case 5 : {
std::cout << "\nLinked List:\n";
sll.traverse();
}
break;
case 6 : {
int data, index;
std::cout << "Enter the data to be searched (any number) : ";
while (!(std::cin >> data)) {
std::cout << "Please enter a valid number: ";
CLEAR_INPUT_BUFFER(std::cin);
}
index = sll.search(data);
if (index == -2) {
std::cout << "\nNo node is present in the linked list.\n";
}
else if (index == -1) {
std::cout << "\nValue not found.\n";
}
else {
std::cout << "\nValue found at node number: " << index;
}
}
break;
}
}
while (choice != 7);
return 0;
}