Stacks

Steven J. Zeil

Last modified: Oct 26, 2023
Contents:

Like vectors and lists, stack and queues are also ordered collections, but the construction and access rules are purposely limited.

1 The Stack ADT

Stacks organize the data in a Last-In, First-Out (LIFO) manner. We can think of a stack as a sequence of elements where we always add to and remove from the same end.

1.1 Overview of Implementation

Stacks can be easily implemented using array/vector-like data structures or via linked lists. You can see both possibilities below.

Actually, implementation of a stack is pretty trivial using either the std::vector<T> or std::list<T> types as an underlying implementation.

Stacks are easily implemented using either arrays, vectors, or linked lists. Try out the linked list implementation of a stack in an animation.

2 std Interface

The stack and queue abstractions do not allow access to arbitrary contained items.

The std library treats stack and queue as special cases by letting you convert

These “converted” ADTs are called “adaptors” in std.

2.1 Using a Stack

stack<string, vector<string> > stk;
stk.push("abc");
stk.push("de");
assert (stk.top() == "de");
stk.pop();
assert (stk.size() == 1);
stk.pop();
assert (stk.empty());

Here are some examples of typical stack manipulation.

(All the asserts should be OK.)

Notice that when instantiating the stack, we specify both the type of elements to go on the stack:

stack<string, vector<string> >

and the sequence to be used as the implementing data structure:

stack<string, vector<string> >

By the way, be careful with things like stack<string, vector<string> >. The blank between the two “>” is important. Without that, C++ assumes that you are writing the >> operator (as in cin >> n;), which would not be legal here.[^This annoying glitch in the language design is fixed in C++11.]

3 Applications & Examples

Stacks are among the most common data structures and crop up in a variety of applications. They are especially useful in parsing and translation of computer languages, mathematics, and other formal notations.

Your text gives examples of some of these, and you will do one in the next assignment.

3.1 Expression Evaluation

Postfix (also known as Reverse Polish Notation or RPN) is a parentheses-free notation for mathematical expressions:

Postfix is easily evaluated using a stack:

Try out the RPN calculator in an animation.

Now, you might find this example a bit artificial-looking. Most people don’t write their expressions out in postfix, preferring the more conventional infix notation. Postfix does have the slight virtue that it can represent any algebraic expression without parentheses.

In fact, back in the not-so-distant past when scientific calculators did not have parentheses keys, anyone using such a calculator was accustomed to entering their intended calculation in postfix form. It’s still common for calculators, compilers, and other software that must process expressions to convert those into postfix form and then use the above algorithm to evaluate the resulting postfix expression.

Conversion to postfix is, itself, generally performed via a stack (or via recursion, which we will later see has a close relationship to stack-based algorithms). For example, to convert a “normal” infix algebraic expression without parentheses into postfix, you could do this:

S = an empty stack;
while (more input available) {
   read the next token, T;
   if T is a variable name or a number, 
     print it;
   else { // T is an operator
      while (S is not empty and T has lower precedence than top operator on S) {
        print top operator on S;
        pop S;
      }
      push T onto S
}
while (S is not empty) {
    print top operator on S;
    pop S;
}

Try this with an expression like “1 + 2*3 + 4”. The output will be “1 2 3 * + 4 +”.

This algorithm can be modified, without too much trouble, to work with parentheses as well.

Another common application of stacks is in converting recursive algorithms to iterative, which we will discuss later.