3-12 The Dynamic Stack

You’ll recall in 3-9 we defined an interface for a stack abstract data type (ADT):

We will now create a DynamicStack class that will use (via composition) a LinkedList to manage the data. Our new class will implement the same StackADT interface (above) as our StaticStack class did – after all, the operations that a stack needs to support should not vary based on the hidden details of how the stack data will be managed.

Here is the DynamicStack code:

On line 1 we are implementing the same StackADT interface that we used for our StaticStack in 3-9.  Line 2 is encapsulating a private reference variable called myList that will refer to a LinkedList data structure.  The empty linked list is actually instantiated in the DynamicStack() no-argument constructor.  This is a great example of composition, where one class includes a reference to an object of another class.

After that you’ll notice that all of the stack methods we are defining are essentially one-liners calling their corresponding LinkedList methods.  This is an excellent application of code reuse!  However, you might wonder what the point of this is — why not just use a linked list? This is a good observation and yes, a linked list could be used in place of a stack.

BUT!  What about the contains() method, or the addLast() or removeLast() methods that you added in 3-11?  Strictly speaking, a stack is not supposed to have such methods but we would have no way to prevent them from being called if we used a linked list.  By creating a DynamicStack class that implements only the methods defined by the StackADT interface, we get a stack data structure that supports exactly the methods we need, and nothing more.

To test the DynamicStack you can use the same code as our StaticStackTest code from 3-9, just change line 8 from:

to:

Notice that we no longer have to specify the size of the required stack anymore – it’s dynamic!  Other than that, the rest of the code should work exactly the same because both the StaticStack and DynamicStack classes implement the same StackADT interface.

You Try!

  1. Using the DynamicStack class, write a program that will ask the user to enter a mathematical expression as a string; for example: [ ( a + b ) – { c * ( b – a ) } ] and determine if the brackets are properly balanced or not.  The supported bracket types should be: ( curved ), { curly }, and [ square ]. When checking an expression to determine if the brackets are balanced, each closing bracket ), }, or ] must be matched with the last non-matched open bracket (, {, or [.  If they are a matching type, then the open bracket is considered matched.  Here are some examples of balanced and unbalanced expressions:

    a ( b )                     // balanced
    a [ b { c } d ] ( e )   // balanced
    a { b { c } d ] e }     // not balanced: ] does not match
    a ( b [ c ] d             // not balanced: missing closing )


    Hint:
    To check if an expression is balanced, you scan it from left-to-right, storing each opening bracket in a stack.  Each time a closing bracket is encountered, the top element in the stack is popped off and compared with the closing bracket.  If they are matching types, scanning continues.  If they do not match, the expression is not balanced and scanning ends.  Once the entire expression is scanned, the stack is examined.  If it is empty, the expression is balanced.  If it is not empty, the expression is not balanced.