STACKS


A stack is a data structure in which elements are added and removed from only one end. At the logical level a stack is an ordered group of elements. The removal of elements from the stack and the addition of elements to it can take place only at the top of the stack. (ex. a stack of cafeteria trays).

A stack is an ordinal structure because at any time, given any two elements in the stack, one is closer to the top. In addition, a stack is a dynamic data structure because the elements in the stack, as well as the size of the stack, may constantly change.

Because elements are added and removed from the top of the stack, the last element added is the first to be removed. This is why the stack is generally known as a LIFO structure -- last in, first out.


STACK OPERATIONS

There is a group of basic stack operations with which the programmer should be familiar:

  1. Clearing the stack or initializing it to the empty state. A stack is empty if it contains no elements.
  2. Adding a new element to the stack -- pushing.
  3. Removing an element from the stack -- popping.
  4. Determining if the stack is empty before attempting to pop an element.

 

Pushing and popping are the major operations involving stacks.

Example -- you are writing a program designed to read in a string of characters followed by a period followed by the same string of characters in reverse order. Your program is to determine if the reversals are correct.

i.e. ABCD.DCBA returns TRUE

       ABCD.ABCD returns FALSE

The code is shown below. Notice that in function reversedString the calls to the stack implementation routines are made but the routines are not included. This is an example of information hiding.


   ' Returns TRUE if the character string preceding the period
   ' is the reverse of the string following the period; FALSE
   ' otherwise. It assumes the presence of a period in the
   ' input and the same number of letters preceding and
   ' following the period.

   Private Function reversedString (ByVal str As String) As Boolean
         Dim stack As clsStack
         Dim matching As Boolean
         Dim noPeriodFound As Boolean
         Dim ctr As Integer
         Dim ch1 As String, ch2 As String

         Call stack.clearStack( ) ' set stack to empty

         ' Extract and Push all characters up to the period.
         noPeriodFound = True
         While noPeriodFound
               ctr = ctr + 1
               ch1 = Mid(str, ctr, 1)
               If (ch1 = ".") Then
                     noPeriodFound = False
               Else
                     Call stack.push(ch1)
               End If
         Wend

         ' Read rest of string and compare characters to those in the stack
         matching = True
         While Not stack.emptyStack( ) And matching
               ctr = ctr + 1
               ch1 = Mid(str, ctr, 1)
               ch2 = stack.pop( )
               If (ch1 <> ch2) Then matching = False
         Wend
         reversedString = matching
   End Function

 


IMPLEMENTATION

The programming language does not provide PUSH and POP, so the programmer must write them.

A stack can be implemented in a variety of ways. Stacks and queues can vary greatly in size during run time, and thus are best implemented as dynamic linked lists. The implementation should not affect the code in the higher levels of the program. Only low-level routines like PUSH and POP, and the declarations for the data structure will need to be modified. 


Declarations

A stack can be represented as a linked list with an external pointer that points to the top of the stack.  The class specification appears below.  Note that in this example the nextNode instance variable is declared as Private, and get and set property methods are provided. 


   '---------------------------------------------------------------------
   ' linkNode class
   '---------------------------------------------------------------------

   ' instance variables

   Private info As Variant
   Private nextNode As linkNode

   ' class methods

   '---------------------------------------------------------------------
   ' Constructor
   '---------------------------------------------------------------------
   Private Sub Class_Initialize( )
      Set nextNode = Nothing
   End Sub

   '---------------------------------------------------------------------
   ' Set node value
   '---------------------------------------------------------------------
   Public Sub setInfo(ByVal newValue As Variant)
      info = newValue
   End Sub

   '---------------------------------------------------------------------
   ' Return node value
   '---------------------------------------------------------------------
   Public Function getInfo( ) As Variant
      getInfo = info
   End Function

   '---------------------------------------------------------------------
   ' Reset nextNode reference
   '---------------------------------------------------------------------
   Public Sub setNextNode(ByRef followingNode As linkNode)
      Set nextNode = followingNode
   End Sub

   '---------------------------------------------------------------------
   ' Return nextNode reference
   '---------------------------------------------------------------------
   Public Function getNextNode( ) As linkNode
      Set getNextNode = nextNode
   End Function

 

 


   '---------------------------------------------------------------------
   ' Class clsStack
   '---------------------------------------------------------------------

   Private stack As linkNode

   '---------------------------------------------------------------------
   ' Initializes the stack to empty.
   '---------------------------------------------------------------------
   Public Sub clearStack( )
      Set stack = Nothing
   End Sub

   '---------------------------------------------------------------------
   ' Returns true if the stack is empty, false otherwise.
   '---------------------------------------------------------------------
   Public Function emptyStack( ) As Boolean
      emptyStack = (stack Is Nothing)
   End Function

   '---------------------------------------------------------------------
   'Inserts node P at the top of the stack.
   '---------------------------------------------------------------------
   Public Sub push(ByVal newValue As Variant)
      Dim newNode As New linkNode
      Call newNode.setInfo(newValue)
      Call newNode.setNextNode(stack)
      Set stack = newNode
   End Sub

   '---------------------------------------------------------------------
   ' Removes the first element from the stack
   '---------------------------------------------------------------------
   Public Function pop( ) As Variant
      Dim nodePtr As linkNode
   
      If emptyStack( ) Then
         MsgBox "Stack empty -- no item to pop.", vbOKCancel + _
               vbExclamation + vbApplicationModal, "Pop Alert"
      Else
         Set nodePtr = stack
         Set stack = stack.getNextNode( )
         pop = nodePtr.getInfo( )
         Call nodePtr.setNextNode(Nothing)
         Set nodePtr = Nothing
      End If
   End Sub

   '---------------------------------------------------------------------
   ' Cycle through a stack, counting each node
   '---------------------------------------------------------------------
   Public Function stackSize( ) As Integer
      Dim ctr As Integer
      Dim Ptr As linkNode
      Set Ptr = stack

      ctr = 0
      If Not emptyStack( ) Then
         While Not Ptr Is Nothing
            ctr = ctr + 1
            Set Ptr = Ptr.getNextNode ( )
         Wend
      End If
      stackSize = ctr
   End Function

   '---------------------------------------------------------------------
   ' Returns the value of the top node in a stack
   '---------------------------------------------------------------------
   Public Function stackTop( ) As Variant
      If Not emptyStack( ) Then stackTop = stack.getInfo( )
   End Function

 



Stack Operations

clearStack:

Clearing the stack is accomplished by setting stack, the external pointer to the stack, to Nothing. It doesn't matter if the stack contains several nodes, because once the external pointer is removed the reference count of the first cell becomes 0 and the garbage collector recovers the node, in the process eliminating the only external pointer to the second item, etc. 


   '---------------------------------------------------------------------
   ' Initializes the stack to empty.
   '---------------------------------------------------------------------
   Public Sub clearStack( )
      Set stack = Nothing
   End Sub



emptyStack:

Testing for an empty stack can be done by checking to see if the external pointer, stack, is equal to Nothing.


   '---------------------------------------------------------------------
   ' Returns true if the stack is empty, false otherwise.
   '---------------------------------------------------------------------
   Public Function emptyStack( ) As Boolean
         emptyStack = (stack Is Nothing)
   End Function

 


PUSH

To add, or push, an element onto a stack, the routine must create a new stack node, set its next pointer to stack, and then move the stack pointer to the new node.


   '---------------------------------------------------------------------
   'Inserts node P at the top of the stack.
   '---------------------------------------------------------------------
   Public Sub push(ByVal newValue As Variant)
      Dim newNode As New linkNode
      Call newNode.setInfo(newValue)
      Call newNode.setNextNode(stack)
      Set stack = newNode
   End Sub


Note the similarity between this Push routine and the pushNode method in the Linked List notes. 

Dim newNode As New linkNode

Call newNode.setInfo(newValue)

 

Call newNode.setNextNode(stack)

Set stack = newNode

 


POP

An item is popped off a stack by setting a pointer to the node referenced by stack, shifting stack to the next element, and returning the first element.


   '---------------------------------------------------------------------
   ' Removes the first element from the stack
   '---------------------------------------------------------------------
   Public Sub pop(ByRef poppedItem As Variant)
      Dim nodePtr As linkNode
   
      If emptyStack( ) Then
         MsgBox "Stack empty -- no item to pop.", vbOKCancel + _
               vbExclamation + vbApplicationModal, "Pop Alert"
      Else
         Set nodePtr = stack
         Set stack = stack.getNextNode( )
         poppedItem = nodePtr.getInfo( )
         Call nodePtr.setNextNode(Nothing)
         Set nodePtr = Nothing
      End If
   End Sub

Set nodePtr = stack

Set stack = stack.getNextNode( )

poppedItem = nodePtr.getInfo( )
Call nodePtr.setNextNode(Nothing)

Set nodePtr = Nothing

<garbage collection>

 


stackSize determines the number of items in the stack.


   '---------------------------------------------------------------------
   ' Cycle through a stack, counting each node
   '---------------------------------------------------------------------
   Public Function stackSize( ) As Integer
         Dim ctr As Integer
         Dim Ptr As linkNode
         Set Ptr = stack

         ctr = 0
         If Not emptyStack() Then
              While Not Ptr.nextNode Is Nothing
                  ctr = ctr + 1
                  Set Ptr = Ptr.nextNode
              Wend
         End If
         stackSize = ctr
   End Function

 


stackTop returns the value of the top node in the stack.


   '---------------------------------------------------------------------
   ' Returns the value of the top node in a stack
   '---------------------------------------------------------------------
   Public Function stackTop( ) As Variant
         If Not emptyStack( ) Then stackTop = stack.getInfo( )
   End Function

 


What good is a stack? A stack is an appropriate data structure when information must be saved and then later retrieved in reverse order. A situation that requires the program to backtrack to some earlier position may be a good occasion to use a stack.

Okay, but when might such a situation arise? Maybe when solving a maze, but what practical use is that? It sounds like stacks will only be of use in a contrived situation. However....

When a program gets to the end of a procedure or function how does it know when to continue? Many systems use a stack to keep track of the return addresses, parameter values or addresses and other information used by subprograms. For instance, when Procedure A is called its calling information is pushed onto the run-time stack. Then, when Procedure B is called from A, B's calling information is pushed onto the top of the stack. B then calls Procedure C, and C's calling information is pushed onto the stack. When C finishes executing, the stack is popped to retrieve the information needed to return to Procedure B. Then B finishes executing and its return address and so forth is popped from the stack. Finally Procedure A completes and the stack is popped again to get back to the main program.


Test Module


   '---------------------------------------------------------------------
   ' Primary Procedure
   '---------------------------------------------------------------------
   Private Sub Form_Load( )
      Dim stack As New clsStack
      Dim p As Variant

      Debug.Print "*=================*"
      Call stack.push("A")
      Debug.Print "Element = " & stack.stackTop( )
      Call stack.push(14)
      Debug.Print "Element = " & stack.stackTop( )
      Call stack.push(10)
      Debug.Print "Element = " & stack.stackTop( )
      Debug.Print "Size = " & stack.stackSize( )
      p = stack.pop( )
      Debug.Print "Element = " & stack.stackTop( )
      Debug.Print "Size = " & stack.stackSize( )
      Call stack.clearStack( )
      Debug.Print "Element = " & stack.stackTop( )
      Debug.Print "Size = " & stack.stackSize( )
   End Sub

Complete Program