CS136, Lecture 13


Quiz on Wednesday: linked lists.


    1. Stacks
      1. Applications of stacks:
        1. Running mazes
        2. Evaluation of arithmetic expressions.
        3. Run-time stacks on computers

Stacks

Stacks can be described recursively:
Stack is either empty or has top element sitting on a stack.

All additions take place at the top of the stack and all deletions take place there as well.

Traditionally refer to addition as "Push" and removal as "Pop" in analogy with spring-loaded stack of trays. Here we'll use both names interchangeably:

public interface Stack extends Linear {
    public void push(Object item);
    // post: item is added to stack
    //       will be popped next if no further push

    public Object pop();
    // pre: stack is not empty
    // post: most recently pushed item is removed & returned

    public void add(Object item);
    // post: item is added to stack
    //       will be popped next if no further add

    public Object remove();
    // pre: stack is not empty
    // post: most recently added item is removed and returned

    public Object peek();
    // pre: stack is not empty
    // post: top value (next to be popped) is returned

    public boolean empty();
    // post: returns true if and only if the stack is empty

    public boolean isEmpty();
    // post: returns true if and only if the stack is empty
}

Applications of stacks:

Running mazes

Keep cells on path from start on a stack. Mark cells when visit them.

See Maze program on-line.

  public void runMaze() 
  {
    success = false;            // No solution yet
    
    current = start;            // Initialize current to start
    current.visit();
    
    path = new StackList(); // Create new path
    path.push(current);     // with start on it
    
    while (!path.empty() && !success)   
      {             // Search until success or run out of cells
                current = nextUnvisited(); // Get new cell to visit
                
                if (current != null) {  // If unvisited cell, 
                  current.visit();      // move to it &
                  path.push(current);   // push it onto path
                  success = current.equals(finish); // Done yet?
                } 
                else    // No neighbors to visit so back up
                {           // Pop off last cell visited
                  current = (Position)path.pop();   
                  if (!path.empty()) // If path non-empty take last 
                                            //  visited as new current
                    current = (Position)path.peek();
                }
      }
  }
Marking of cells and use of stack keeps from searching around in circles and yet not missing any possible paths.

Evaluation of arithmetic expressions.

Some machines have stack based machine language instructions.

E.g. PUSH, POP, ADD (pop off top two elements from stack, add them and push result back onto stack), SUB, MULT, DIV, etc.

Ex. Translate X * Y + Z * W to:

  PUSH X
  PUSH Y
  MULT
  PUSH Z
  PUSH W
  MULT
  ADD
Trace result if X = 2, Y = 7, Z = 3, W = 4.

How do you generate this code?

Write expression in postfix form: operator after operands

E.g. 2 + 3 -> 2 3 +

General algorithm to convert:

1. Write expression fully parenthesized.

2. Recursively move operator after operands, dropping parentheses when done.

E.g.

X * Y + Z * W -> (X * Y) + (Z * W) -> (X Y *) (Z W *) +

-> X Y * Z W * +

Note parentheses no longer needed. Corresponds to reverse Polish calculator.

Once in postfix, easy to generate code as follow:

If operand, generate PUSH command

If operator, generate command to do operation.

Therefore above expression compiled as shown earlier: PUSH X, PUSH Y, MULT, ...

Straightforward to write a computer program using stacks to use these instructions (or even the original postfix expression) to calculate values of arithmetic expressions.

On such a calculator, "PUSH" key is usually labelled ENTER.

Also usually only first operand must be "ENTER"ed. Rest automatically "ENTER"ed after type and then hit operator key.

This will be your next homework assignment!

Interestingly, algorithm to convert expression to postfix form can either be done recursively (as above) or using a stack.

Notice all operands appear in same order as started - only operations move. Commands to transform above expression (working on it from left to right):

  OUTPUT X
  PUSH *
  OUTPUT Y
  POP and OUTPUT operator
  PUSH +
  OUTPUT Z
  PUSH *
  OUTPUT W
  POP and OUTPUT operator
  POP and OUTPUT operator
(Other rules - "(" is always pushed onto stack, ")" causes operators to be popped and output until pop off topmost "(" on stack. )

Big question: When do you push one operator on top of another and when do you pop off topmost operator before pushing on new one?

Answer given in terms of precedence of operators!

Bring answer to class tomorrow!

Run-time stacks on computers

All computers use a run-time stack in order to keep track of procedure, function, or method invocations.

Every time a procedure or a function is called, an "activation record" is created which contains slots for all parameters, local variables, and the address of an instruction where execution should be resumed after the routine is through executing.

When a procedure is called, the activation record is pushed onto the run-time stack, and when it returns, the corresponding activation record is popped.

Why is a stack the correct data structure for this?
Could you call p and inside p call q, and yet have p return before q?

Using the debugger, you can actually see the current contents of the run-time stack.