A stack ADT implemented using pointers

 

We are going to implement the stack ADT using a linked list.

 

 

 

17

 

 

 

21

 
top                        

 

 

 

In the above example, there is a pointer called top that points to a node containing the int 21.  The node that contains 21 points to a node containing the int 17.

 

This stack is a stack of int values with 17 at the bottom of the stack, and 21 at the top of the stack. The 17 was pushed on the stack first, then 21 was pushed on the stack.

 

 

Each node will have two data members, called item and next. 

item stores an int;

next points to a node.

 

struct Node

{

    int   item;

    Node* next;

};

 

 

Node

 

 

 

 

 

top is a Node* pointing to the node that contains the topmost item on the stack .

 

An empty stack has no nodes.  For an empty stack, top will contain a NULL pointer value, indicating that it does not point to any node.  In diagrams, we draw the NULL value with a diagonal line from the to bottom left to the top right.

 

top                        

 

 

 

After pushing 17 on an empty stack, we obtain:

 

 

 

17

 
top                        

 

 

 


And if we now push 21, we obtain a stack with two items.  The 17 has been pushed down, and 21 has been pushed on top of the stack.

 

 

 

17

 

 

 

21

 
top                        

 

 

 

The stack ADT has an explicit default constructor, an explicit copy constructor, an explicit destructor, methods for pushing and popping the stack, a method for viewing the top item, and methods for determining if a stack is empty or full.

 

class Stack {

public:   

    Stack();

    Stack( const Stack& srcStack );

    ~ Stack();

    void Push( /* in */ int newItem );

    int Top() const;

    int Pop();

    bool IsEmpty() const;

    bool IsFull() const;

private:

    struct Node

    {

        int   item;

        Node* next;

    };

    Node* top;

};

 

This is the same public stack interface (except for the addition of the explicit copy constructor and explicit destructor) that we used for the array implementation of the stack ADT.

 

Implementation of the stack constructor

 

We initialize the stack's top data member to NULL.

 

top                        

 

 

 


Stack::Stack()

{

    top = NULL;

}

 

Implementation of  void Push( /* in */ int newItem )

 

First, we create a new node to store the new item, then this new node must be inserted immediately in front of the topmost node.

 

 

 

17

 
top                        

 

 

 


                       insert here

                              

 

 

 

 


Step 1.  Create a new node. 

 

Node* newPtr = new Node;

 

 

 

17

 
top                        

 

 

 


                      

                              

 

 

 


   

 

 
 

 


    newPtr

 

 

 


Step 2.  Store the new item in the new node. 

 

                        newPtr->item = newItem;

 

 

 

17

 
top                        

 

 

 


                       

                              

 

 

 


   

 

 
 

 


    newPtr

 

Step 3.  Link the new node to the topmost node.

 

                        newPtr->next = top;

 

 

 

17

 
top                        

 

 

 


                      

                              

 

 

 


   

 

 
 

 


    newPtr

 

            Dotted arrows                      represent an assignment (copy) of a value.

            Solid arrows                        represent pointers.


Step 4.  Link top to the new node.

 

                        top = newPtr;

 

 

 

17

 
top                        

 

 

 

 

 

 

 

 

 

 

 


       newPtr

 

 

The above code also works when the stack was empty just before the call of Push().

 

Step 1.  Create a new node. 

 

Node* newPtr = new Node;

 

 

top                        

 

 

 


                      

                              

 

 

 


 

 
   

 

 

    newPtr

 

 

 


Step 2.  Store the new item in the new node. 

 

                        newPtr->item = newItem;

 

top                        

 

 

 


                      

                              

 

 

 


   

 

 
 

 


    newPtr

 

Step 3. 

 

                        newPtr->next = top;

 

top                        

 

 

 


                      

21

 

 

 
                              

 

 

 


   

 

 
 

 


    newPtr

 

 


Step 4.  Link top to the new node.

 

                        top = newPtr;

 

top                        

 

 

 

 

 

 

 

 

 

 


    newPtr

 

 

The complete code for the  Push method is:

 

void Stack::Push( /* in */ int newItem )

{

    Node* newPtr = new Node;

 

    newPtr->item = newItem;

    newPtr->next = top;

    top          = newPtr;

}

 

The new node is created in the heap ( = dynamic store) and continues to exist even after Push() finishes execution.

 

The newPtr pointer variable is local to the Push method, so it is created when Push() is called; and it is automatically destroyed when Push() finishes execution.

 

 

Implementation of int Top( ) const

 

Top() returns a copy of the topmost item.  (The precondition is that the stack contains at least one item, so the implementer does not check that an item exists.)

 

int Stack::Top() const

{

    return top->item;

}

 


Implementation of int Pop( )

 

Pop removes and returns the topmost item from a stack.  The node that stored the topmost item must be returned to the heap.  We must "recycle" the memory used by variables that we no longer need.

 

(The precondition is that the stack contains at least one item.)

 

 

 

17

 

 

 

21

 
top                        

 

 

 


                                               remove this node

 

 

Step 1.  Make a copy of the item in the topmost node.  (Later we will return this value to the caller.)

 

          int item = top->item;

 

 

Step 2.  Declare a local pointer, and point it to the topmost node.

 

          Node* oldPtr = top;

 

         

 

 

17

 

 

 

21

 
top                        

 

 

 


                                              

 

 
 

 

 


                              oldPtr

 

Step 3.  Relink top to the node that is just below the topmost node.

 

                        top = top->next;

 


 

 

17

 

 

 

21

 
top

 

 

 

 

 

 

 


                              oldPtr

 


Step 4.  Delete the old topmost node.

 

                        delete oldPtr;

 

 


 

 

17

 
top                         

 

 

 


                                              

 

 
 

 

 


                              oldPtr

 

Step 5.  Return the saved item.

 

          return item;

 

The above code also works when the stack contains exactly one item prior to the call of Pop().

 

 

 

 

21

 
top                        

 

 

 


                                               remove this node

 

 

Step 1.  Make a copy of the item in the topmost node.

 

          int item = top->item;

 

Step 2.  Declare a local pointer, and point it to the topmost node.

 

          Node* oldPtr = top;

 

         

 

 

21

 
top                        

 

 

 


                                              

 

 
 

 

 


                              oldPtr

 


Step 3. 

 

                        top = top->next;

 

 

 

21

 
top                        

 

 

 


                                              

 

 
 

 

 


                              oldPtr

 

Step 4.  Delete the old topmost node.

 

                        delete oldPtr;

 

top                        

 

 

 


                                               

 

 
 

 

 


                              oldPtr

 

Step 5.  Return the saved item.

 

          return item;

 

The complete code is:

 

int Stack::Pop()

{

    int   item   = top->item;

    Node* oldPtr = top;

 

    top = top->next;

    delete oldPtr;

    return item;

}

 

 


Implementation of bool IsEmpty( ) const

 

Return true if the stack is empty; return false if the stack isn't empty.

 

bool Stack::IsEmpty() const

{

    return ( top == NULL );

}

 

Implementation of bool IsFull( ) const

 

Return true if the stack is full; return false if the stack isn't full.  The stack can only become full if we exhaust the heap.  We are going to assume that the heap never becomes empty, so IsFull() always returns false.

 

bool Stack::IsFull() const

{

    return false;

}

 

 

Implementation of the destructor.

 

The destructor must return all dynamically allocated memory to the heap.

 

The algorithm repeatedly pops the stack until it is empty.

 

Stack::~Stack()

{

    Node* oldPtr;

 

    while ( top != NULL )

    {

        oldPtr = top;

        top    = top->next;

        delete oldPtr;

    }

}

 


Implementation of the copy constructor.

 

(The copy constructor is executed when a stack is initialised from another stack, or when a stack is passed by value to a function.

 

void MyFunc( /* in */ Stack );

 

Stack stack1;

stack1.Push(17);

stack1.Push(21);

 

Stack stack2 = stack1; // copy constructor called here

MyFunc( stack1 ); // copy constructor called here

...

void MyFunc( /* in */ Stack stack )

{

    ...

}

 

The copy constructor has to clone all of the nodes from the source stack (stack1 in the above code.)

 

The algorithm iterates through the linked list of nodes from the source stack, and for each node, makes a copy of the node, and appends the copy to the end of the new stack.

 

Stack::Stack( const Stack& srcStack )

{

    Node* newPtr;

    Node* rear = NULL;

   

    top = NULL;

 

    for ( Node* srcPtr = srcStack.top;

          srcPtr != NULL;

          srcPtr = srcPtr->next )

    {

        newPtr = new Node;

       

        newPtr->item = srcPtr->item;

        newPtr->next = NULL;

        if ( rear == NULL )

            top = newPtr;

        else

            rear->next = newPtr;

        rear = newPtr;

    }

}