反转使用链接列表实现的堆栈

时间:2015-03-12 04:32:31

标签: c++

这是一个使用链表实现堆栈的非常简单的程序。 请帮助我找出导致程序崩溃的逻辑错误。

class LLStack {
    public:
        struct Node {
            int data;
            Node* next;
            Node(int n) {
                data = n;
                next = 0;
            }
            Node(int n, Node* node) {
                data = n;
                next = node;
            }
        };
        LLStack();
        LLStack(const LLStack&);
        LLStack& operator = (const LLStack&);
        ~LLStack();
        void push(int);
        int pop();
        int top();
        bool isEmpty();
        void flush();

    private:
        Node* head;

};

LLStack::LLStack() {
    head = 0;
}

LLStack::LLStack(const LLStack& s) {
    head = new Node(NULL);
    head->data = s.head->data;
    head->next = new Node(*(s.head->next));
}

LLStack::~LLStack() {
    this->flush();
}

LLStack& LLStack::operator = (const LLStack& s) {
    this->head = new Node(NULL);
    this->head->data = s.head->data;
    this->head->next = new Node(*(s.head->next));
    return *this;
}

void LLStack::push(int x) {
    if (head == 0) head = new Node(x);
    else {
        Node* temp = new Node(x, head);
        head = temp;
    }
}

int LLStack::pop() {
    if (head == 0) {
        cout << "\n\nNo elements to pop\n\n";
        return -1;
    }
    else {
        Node* temp = head;
        int n = temp->data;
        head = temp->next;
        delete temp;
        return n;
    }
}

int LLStack::top() {
    if (head == 0) {
        cout << "\n\nNo elements in the stack\n\n";
        return -1;
    }
    else {
        return head->data;
    }
}

bool LLStack::isEmpty() {
    return (head == 0);
}

void LLStack::flush() {

    if (head == 0) {
        cout << "\n\nNo elements in the Stack to flush\n\n";
        return;
    }
    cout << "\n\nFlushing the Stack:  ";
    Node* temp = 0;
    while (head != 0) {
        temp = head;
        cout << temp->data << "  ";
        head = head->next;
        delete temp;
    }
    cout << endl << endl;
}

这是麻烦制造者的功能:

void reverseStack(LLStack& s1) {
    LLStack s2;
    while (!s1.isEmpty()) {
        s2.push(s1.pop());
    }
    s1 = s2;
}

int main() {

    LLStack s;
    s.push(1);
    s.push(2);
    s.push(3);
    s.push(4);
    s.push(5);
    reverseStack(s);
    cout << "\n\nFlushing s:\n";
    s.flush();
    system("pause");
    return 0;
}

我已经实现了自己的复制构造函数和复制赋值运算符。我不明白为什么它会在跑步时崩溃。在刷新时,它会在崩溃前显示垃圾值。

1 个答案:

答案 0 :(得分:0)

问题在于您的复制赋值运算符。考虑:

void reverseStack(LLStack& s1) {
    LLStack s2;
    while (!s1.isEmpty()) {
        s2.push(s1.pop());
    }
    s1 = s2;
}

一切正常,直到你从函数返回,此时调用s2的析构函数。析构函数调用flush(),删除s2的所有堆栈元素。在您的复制赋值运算符(以及复制构造函数)中,您创建了两个节点:headhead->next;其余节点在两个堆栈之间共享,因此在删除s2后,s1.head->next->next指向已删除的节点,但您仍尝试访问它。

解决方案是让复制赋值运算符(和复制构造函数)创建堆栈的正确深层副本,而不仅仅是前两个元素,这样(也负责自我赋值):

LLStack& LLStack::operator=(const LLStack& s) {
    if (this==&s) return *this; // self assignment
    flush();  // avoid memory leak
    head = new Node(*s.head);
    Node* s_ptr = s.head;
    Node* t_ptr = head;
    while (s_ptr->next) {
        t_ptr->next = new Node(*s_ptr->next);
        s_ptr = s_ptr->next;
        t_ptr = t_ptr->next;
    }
    return *this;
}

请记住,复制构造函数也应该这样做。