Introductory Programming in Python: Lesson 30
Advanced Data Structures: Stacks

[Prev: Advanced Data Structures: Queues] [Course Outline] [Next: Advanced Data Structures: Trees]

Last In, First Out

A stack is an order collection of objects which can only be operated on in two ways. We can add an object to the end of the collection, known as pushing an object onto the stack, or we can remove the last item on the stack, known as popping the stack. We can only inspect the last item on the stack too. The rest of the collection is hidden from us, strictly speaking, although this depends greatly on the implementation of the stack. The airport luggage example illustrates the working of a stack. The first person to check their baggage in finds that their baggage is the last available at the other end on the conveyor belt. Sometimes being late does pay off. In fact the baggage will come out in the reverse order it was put in.

Stacks are one of those tools in every programmer's toolkit. Which is not to say they can solve every problem, but they are found in a surprising variety of solutions. The key concept to understand about a stack is that they are good for reordering things in a variety of ways, not just for reversing things. They are also good a 'remembering things' so they can be undone, hence the term 'undo stack'.

Lists as Stacks

Python offers us a convenient set of methods to operate lists as stacks.

Python 2.4.3 (#1, Oct	2 2006, 21:50:13) 
[GCC 3.4.6 (Gentoo 3.4.6-r1, ssp-3.4.5-1.0, pie-8.7.9)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> stack = []
>>> stack.append(3)
>>> stack
[3]
>>> stack.append(2)
>>> stack
[3, 2]
>>> stack.append(1)
>>> stack
[3, 2, 1]
>>> stack.pop()
1
>>> stack.pop()
2
>>> stack.pop()
3
>>>

Infix to Postfix Conversion: A Worked Example

There are various ways to write down an arithmetic expression. We are used to a method know as infix notation, called such because operator's are written in between operands. Infix notation suffers a severe drawback, in that the precedence of operators is implicit and changes the order of evaluation. Consider the expression '4*(2+3)'. We cannot simply evaluate this expression from left to right. We want to change the order in which it is evaluated to match the order of precedence. Order changing, sounds like a job for soooperr-stack!

The other two notations are called prefix and postfix notation respectively. Prefix notation lists operators prior to their operands, whilst postfix lists operators after their respective operands. We would write the former expression as '*4+23' or '423+*' in prefix and postfix notation respectively. Although basically equivalent except for order, computer science has settled on postfix as a preferred method for evaluating expressions. Note that the precedence of the operators in in the post- and pre-fix notations does not need brackets to define a change in precedence. We can evaluate these expressions from left to right, as such in the case of prefix notation

  1. * indicates we must multiply the next two operands, and replace them and the operator with the resulting value
  2. 4 is the first operand
  3. + indicates we must add the next two operands and replace the operator and it's operands with the resulting value
  4. 2 is the first operand of the plus
  5. 3 is the second operand of the plus
  6. 2+3 = 5, so we replace the +23 part with 5 yielding '*45'
  7. 5 is the second operand of the multiply
  8. 4*5 = 10, so we replace the *45 part with 20 yielding '20' which requires no further evaluation, as there are no more operators.

Since it is trivial to evaluate a postfix (or prefix) expression, we want to write a function that converts an infix expression to a postfix one. For the sake of example, we shall only allow single digit numbers, and the binary operators '+', '-', '*', '/', and parentheses.

def postfix(infix):
    operator_stack = []
    output_queue = ''

    for c in infix:
        if c.isdigit():
            output_queue += c
        elif c in ['+', '-', '*', '/']:
            while len(operator_stack) > 0 
                    and operator_stack[len(operator_stack)-1] in ['*', '/'] 
                    and c in ['+', '-']:
                output_queue += operator_stack.pop()
            operator_stack.append(c)
        elif c == '(':
            operator_stack.append(c)
        elif c == ')':
            o = operator_stack.pop()
            while o != '(':
                output_queue += o
                o = operator_stack.pop()
    while len(operator_stack) > 0:
        output_queue += operator_stack.pop()
    
    return output_queue

Exercises

[Prev: Advanced Data Structures: Queues] [Course Outline] [Next: Advanced Data Structures: Trees]