C ++堆栈使用链接列表双删除问题

时间:2016-10-16 20:45:52

标签: c++ linked-list stack delete-operator

我一直在四处寻找,但我找不到解决方案。对于我的数据结构课程,我被要求使用链表创建堆栈。在大多数情况下它运作良好,我的教授甚至给了我一个24/25的任务,但它一直困扰我,它仍然崩溃。我怀疑问题出在复制构造函数或pop操作中。这是头文件:

{
    width: auto;
    height: auto;
}

这是实施文件:

/*******************************************************************************
***  DESCRIPTION :  This file implements a stack ADT using a linked list.    ***
***                 Besides the standard constructor, copy, and destructor   ***
***                 functions, the available functions include:              ***
***                     * push - pushes data onto the stack                  ***
***                     * pop - pops data from the stack                     ***
***                     * peek - view the top element on the stack           ***
***                     * view - output every element on the stack           ***
*******************************************************************************/

#ifndef _KIELASJC2_H
#define _KIELASJC2_H

// User specified element type
typedef char ElementType;

class StackType{
    // Exportable definitions
    public:
        // Constructor
        StackType();
        // Copy constructor
        StackType( StackType& copyStack );
        // Destructor
        ~StackType();
        // Push data onto the stack
        void push( const ElementType pushElem );
        // Pop data from the stack
        void pop( ElementType& popElem );
        // Peek the top element on the stack without changing the stack
        void peek( ElementType& peekElem );
        // Look at every element in the stack without changing the stack
        void view();

    private:
    // Non-exportable definitions
        struct NodeType;
        typedef NodeType* PointerType;
        struct NodeType{
            ElementType element;
            PointerType next;
        };
        PointerType theTop;
        bool isEmpty( PointerType tempNode );
        bool isFull( PointerType tempNode );
};

#endif

这是我的测试代码:

/*******************************************************************************
***  DESCRIPTION :  This file implements a stack ADT using a linked list.    ***
***                 Besides the standard constructor, copy, and destructor   ***
***                 functions, the available functions include:              ***
***                     * push - pushes data onto the stack                  ***
***                     * pop - pops data from the stack                     ***
***                     * peek - view the top element on the stack           ***
***                     * view - output every element on the stack           ***
***                 It also includes two private functions:                  ***
***                     * isEmpty - checks to see if the stack is empty      ***
***                     * isFull - checks to make sure temp wasn't NULL      ***
*******************************************************************************/

#include <iostream> // For using cout
#include <iomanip> // For manipulating output
#include "kielasjc2.h" // Header to this implementation file

// Debug
#define DEBUG 0

// Namespace
using namespace std;

/*******************************************************************************
***  FUNCTION Constructor                                                    ***
********************************************************************************
***  DESCRIPTION :  Initializes the class by setting theTop and tempNode to  ***
***                 NULL.                                                    ***
***  INPUT ARGS  :  NONE                                                     ***
***  OUTPUT ARGS :  NONE                                                     ***
***  IN/OUT ARGS :  NONE                                                     ***
***  RETURN      :  NONE                                                     ***
*******************************************************************************/
StackType::StackType() {
    // Initialize both top and temp to NULL
    theTop = NULL;

}

/*******************************************************************************
***  FUNCTION Copy Constructor                                               ***
********************************************************************************
***  DESCRIPTION :  Creates a copy of the stack linked list by popping all   ***
***                 elements in the first stack into a temporary stack. All  ***
***                 elements from the temporary stack are then pushed back   ***
***                 into the copied stack and original stack.                ***
***  INPUT ARGS  :  NONE                                                     ***
***  OUTPUT ARGS :  StackType& copyStack - copy of the original stack        ***
***  IN/OUT ARGS :  NONE                                                     ***
***  RETURN      :  NONE                                                     ***
*******************************************************************************/
StackType::StackType( StackType& copyStack ) {
    // Point the top to NULL
    theTop = NULL;
    // Create a temporary stack
    StackType tempStack;
    // Create a temporary element
    ElementType tempElem;
    // Create a temporary pointer to the top 
    //PointerType tempNode = theTop;
    // Create a temporary pointer to the the top of the copy stack
    //PointerType tempTempNode = tempStack.theTop;
    //PointerType copyTempNode = copyStack.theTop;

    // Loop through the entire stack and pop each element into the temp stack
    while ( !copyStack.isEmpty( copyStack.theTop ) ) {
        // Pop the current stack
        copyStack.pop( tempElem );
        // Push the popped element into the temp stack
        tempStack.push( tempElem );
    }

    // Refill the current and copy stacks with the temp stack
    while (!tempStack.isEmpty( tempStack.theTop )){
        // Pop the temp stack
        tempStack.pop( tempElem );
        // Push the popped element onto the current newly copied stack
        push( tempElem );
        // Push the same popped element back onto the copy stack
        copyStack.push( tempElem );
    }

}

/*******************************************************************************
***  FUNCTION Destructor                                                     ***
********************************************************************************
***  DESCRIPTION :  Destroys the current stack by popping every element.     ***
***  INPUT ARGS  :  NONE                                                     ***
***  OUTPUT ARGS :  NONE                                                     ***
***  IN/OUT ARGS :  NONE                                                     ***
***  RETURN      :  NONE                                                     ***
*******************************************************************************/
StackType::~StackType() {
    // Create a temporary element just so we can call pop
    ElementType tempElem;

    #if DEBUG
        cout << "[+] DEBUG: FUNCTION - Destructor" << endl;
        cout << "[+]        theTop: " << theTop << endl;
    #endif

    // While the stack is not empty, pop
    while (!isEmpty( theTop )) {
        // Pop the top node
        pop( tempElem );
    }

}

/*******************************************************************************
***  FUNCTION push                                                           ***
********************************************************************************
***  DESCRIPTION :  Pushes the input element onto the current stack.         ***
***  INPUT ARGS  :  const ElementType pushElem - element to be pushed onto   ***
***                     the current stack.                                   ***
***  OUTPUT ARGS :  NONE                                                     ***
***  IN/OUT ARGS :  NONE                                                     ***
***  RETURN      :  NONE                                                     ***
*******************************************************************************/
void StackType::push( const ElementType pushElem ) {
    // Create a pointer to a new node
    PointerType tempNode = new (nothrow) NodeType;

    // Verify that the node isn't full
    if (isFull( tempNode )) {
        // Tell the user if new memory couldn't be allocated
        cout << "[!] ERROR: (push) New dynamic node could not be created.";
        cout << endl;
        return;
    }

    #if DEBUG
        ElementType tempElem;
        cout << "[+] DEBUG: FUNCTION - push" << endl;
        peek( tempElem );
        cout << "[+]        top before the push: " << tempElem << endl;
        cout << "[+]        Top ptr before: " << theTop << endl;
    #endif

    // Set the temporary node element to the element being pushed
    tempNode->element = pushElem;
    // Set the next pointer to the top
    tempNode->next = theTop;

    // If these two lines were flipped, the code works, but it creates a memory 
    // leak, so that doesnt work either
    theTop = tempNode;
    tempNode = NULL;

    #if DEBUG
        peek( tempElem );
        cout << "[+]        Top ptr after:  " << theTop << endl;
        cout << "[+]        top after the push:  " << tempElem << endl;
    #endif

}

/*******************************************************************************
***  FUNCTION pop                                                            ***
********************************************************************************
***  DESCRIPTION :  Pops the top element off of the current stack.           ***
***  INPUT ARGS  :  NONE                                                     ***
***  OUTPUT ARGS :  ElementType& popElem - Stores the element that was       ***
***                     popped from the stack.
***  IN/OUT ARGS :  NONE                                                     ***
***  RETURN      :  NONE                                                     ***
*******************************************************************************/
void StackType::pop( ElementType& popElem ) {
    // Create a temporary pointer
    PointerType tempNode = theTop;

    // Point temp to the same node the top is pointing to
    //tempNode = theTop;

    // Make sure the stack isn't empty
    if (isEmpty( tempNode )) {
        // Tell the user if the stack is empty
        cout << "[!] ERROR: (pop) No node available to pop, stack is empty.";
        cout << endl;
        return;
    }

    #if DEBUG
        cout << "[+] DEBUG: FUNCTION - pop" << endl;
        cout << "[+]        Top ptr before: " << theTop << endl;
    #endif

    // Point the top to the next node
    theTop = theTop->next;
    // Derefrence the next node of the current node being popped
    tempNode->next = NULL;
    // Pop the element into popElem
    popElem = tempNode->element;
    // Delete the node
    delete tempNode;
    // Point temp back to NULL
    tempNode = NULL;

    #if DEBUG
        cout << "[+]        Top ptr after:  " << theTop << endl;
        cout << "[+]        Element being popped: " << popElem << endl;
    #endif

}

/*******************************************************************************
***  FUNCTION peek                                                           ***
********************************************************************************
***  DESCRIPTION :  Looks at the top element of the current stack by popping ***
***                 it. The element is then pushed back onto the top of the  ***
***                 current stack.                                           ***
***  INPUT ARGS  :  NONE                                                     ***
***  OUTPUT ARGS :  ElementType& peekElem - stores the element being peeked. ***
***  IN/OUT ARGS :  NONE                                                     ***
***  RETURN      :  NONE                                                     ***
*******************************************************************************/
void StackType::peek( ElementType& peekElem ) {
    // Create a temporary pointer
    //PointerType tempNode;

    // Point temp to the top
    //tempNode = theTop;

    // Make sure the stack isn't empty
    if (isEmpty( theTop )) {
        // Tell the user if the stack is empty
        cout << "[!] ERROR: (peek) Stack is empty, no element to peek at.";
        cout << endl;
        // Return a null value if the stack is empty
        peekElem = '\0';
        return;
    }

    // Pop the top element into peekElem
    pop( peekElem );

    // Push the popped element back onto the top of the stack
    push( peekElem );

    #if DEBUG
        cout << "[+] DEBUG: FUNCTION - peek" << endl;
        cout << "[+]        Peeked value: " << peekElem << endl;
    #endif

}

/*******************************************************************************
***  FUNCTION view                                                           ***
********************************************************************************
***  DESCRIPTION :  Shows the user every element on the current stack by     ***
***                 popping every element and pushing them into a temporary  ***
***                 stack. Once the user has seen the contents of the stack, ***
***                 the elements on the temporary stack are popped and       ***
***                 pushed back onto the current stack.                      ***
***  INPUT ARGS  :  NONE                                                     ***
***  OUTPUT ARGS :  NONE                                                     ***
***  IN/OUT ARGS :  NONE                                                     ***
***  RETURN      :  NONE                                                     ***
*******************************************************************************/
void StackType::view() {
    // Create a temporary stack
    StackType tempStack;
    // Create a temporary element
    ElementType tempElem;
    // Point a temporary node to the top
    //PointerType tempNode = theTop;
    // Point a temporary node to the top of the copy stack
    //PointerType copyTempNode;

    // View output for the user
    cout << "The Top -> ";

    // Loop through the entire stack and pop each element into the temp stack
    while (!isEmpty( theTop )) {
        // Pop the current stack
        pop( tempElem );
        // Push the popped element into the temp stack
        tempStack.push( tempElem );
        // Output the elements as the stack is popped
        cout << tempElem << " -> ";
    }

    cout << "The Bottom" << endl;

    // Refill the current stack with the temp stack
    while (!tempStack.isEmpty( tempStack.theTop )){
        // Pop the temp stack
        tempStack.pop( tempElem );
        // Push the popped element onto the current stack
        push( tempElem );
    }

}

/*******************************************************************************
***  FUNCTION isEmpty                                                        ***
********************************************************************************
***  DESCRIPTION :  Checks to see whether or not the stack is empty.         ***
***  INPUT ARGS  :  NONE                                                     ***
***  OUTPUT ARGS :  NONE                                                     ***
***  IN/OUT ARGS :  NONE                                                     ***
***  RETURN      :  bool true/false - true if the stack is empty, false      ***
***                     if the stack is not empty.                           ***
*******************************************************************************/
bool StackType::isEmpty( PointerType tempNode ) {
    // If the top isn't pointing to NULL, our stack isn't empty yet
    if (tempNode != NULL) {
        return false;
    } else {
        return true;
    }

}

/*******************************************************************************
***  FUNCTION isFull                                                         ***
********************************************************************************
***  DESCRIPTION :  Checks to see if the current stack is full after         ***
***                 attempting to allocate new memory for the next node.     ***
***                 This will only provide a relevent value if it is used    ***
***                 immediately after trying to allocate memory for a new    ***
***                 node being pointed to by the tempNode.                   ***
***  INPUT ARGS  :  NONE                                                     ***
***  OUTPUT ARGS :  NONE                                                     ***
***  IN/OUT ARGS :  NONE                                                     ***
***  RETURN      :  bool true/false - true if the tempNode is NULL, false    ***
***                     if a pointer value was assigned to tempNode.         ***
*******************************************************************************/
bool StackType::isFull( PointerType tempNode ) {
    // If temp isn't NULL, we have successfully allocated memory.
    // This function should only be used immediately after allocating new
    // memory to the tempNode.
    if (tempNode != NULL) {
        return false;
    } else {
        return true;
    }

}

最后,这是我收到的输出(包括错误):

#include <iostream>
#include "kielasjc2.h"

using namespace std;

int main(int argc, char* argv[]) {
    StackType stack;
    StackType stack2;

    stack.push('a');

    stack2 = stack;

    cout << "Stack: ";
    stack.view();
    cout << endl;

    cout << "Stack2: ";
    stack2.view();
    cout << endl;

}

1 个答案:

答案 0 :(得分:0)

stack2 = stack;不会调用您的复制构造函数。它调用编译器生成的复制赋值运算符,它只执行stack2.theTop = stack.theTop。于是你最终得到两个对象,认为它们都拥有相同的节点集。

另请参阅:https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)