单向链表删除头节点后指向垃圾值的头指针

Head pointer pointing to garbage value after deleting node from head in singly linked list

我正在尝试用 C++ 实现单向链表。 delete temp; 语句之前的 deleteFromHead() 一切正常。在语句之后,headnext 都开始指向一些垃圾值。由于这是从头部删除节点的标准方法,所以我无法找出问题所在。 这是完整的代码:

#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,因此 您正在清除整个节点列表 ,使 headtail指针.

切勿使用递归析构函数!释放列表中的下一个节点不应该是 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;
}