Stacks Cmput Lecture 18 Department of Computing Science University of Alberta ©Duane Szafron 2000 Some code in this lecture is based on code from the book: Java Structures by Duane A. Bailey or the companion structure package Revised 2/24/00
©Duane Szafron About This Lecture In this lecture we will learn about a group of data structures called linear structures and specifically one representative from the group called a Stack.
©Duane Szafron Outline Linear Structure Interface Stack Interface Maze - An example of using a Stack Vector Implementation of Stack List Implementation of Stack
©Duane Szafron A Linear Structure A Linear Structure is a non-indexed container object (in fact a Store) that can grow and shrink one element at a time. However, it is not specified whether the container shrinks at the same end that it grows. "Fred""Barney""Wilma" "Fred""Barney""Wilma"”Betty""Fred""Barney""Wilma" ”Barney"”Wilma"”Betty"
©Duane Szafron Linear Container Hierarchy In the structure package the following interface hierarchy appears. Store Linear StackQueue In the java.util package Stack is a sub- class of Vector, not an interface
©Duane Szafron Structure Interface - Store public interface Store { public int size (); //post: returns the number of elements contained in // the store. public boolean isEmpty (); // post: returns the true iff store is empty. public void clear (); // post: clears the store so that it contains no elements. } code based on Bailey pg. 18
©Duane Szafron Structure Interface - Linear public interface Linear extends Store { public void add (Object anObject); // pre: anObject is non-null // post: the object is added to the container. The // consistent replacement policy is not specified public Object peek (); // pre: container is not empty /* post: returns the next object to be removed, but does in not remove it */ public Object remove (); // pre: container is not empty // post: removes an object from the container and returns it } code based on Bailey pg. 127
©Duane Szafron Structure Interface - Stack 1 public interface Stack extends Linear { public void add (Object anObject); // post: the object that is added will be popped next if // nothing else is added. Same operation as push public void push (Object anObject); // post: the object that is added will be popped next if // nothing else is pushed. Same operation as add public Object remove (); // pre: stack is not empty // post: removes the most recently added object and // returns it. Same operation as pop code based on Bailey pg. 128
©Duane Szafron Structure Interface - Stack 2 public Object pop (); // pre: stack is not empty // post: removes the most recently pushed object and // returns it. Same operation as remove public Object peek (); // pre: stack is not empty // post: returns the next object to be removed, but does in // not remove it } code based on Bailey pg. 128
©Duane Szafron Stack Example - Stack frames One common application of Stacks is to hold the program state during the execution of a method (or procedure or function). In this case, the objects on the Stack are stack frames. In recursive calls, many stack frames can be created in the virtual machine. The textbook shows how an application level stack can simulate recursion and eliminate the actual recursion in the virtual machine.
©Duane Szafron Stack Example - Maze Algorithm One common approach to solving search problems is to use a Stack to hold “unsearched” paths. 0 S F Select the start square as the current square. Repeat as long as the current square is not null and is not the finish square: –“Visit” the square. –Push one square on the stack for each unvisited legal move from the current square. –Pop the stack into current square or bind the current square to null if the stack is empty. If the current square is the goal we are successful, otherwise there is no solution
©Duane Szafron Stack Example - Maze Trace 1 0 S F P0 P1 0 S F P1 P6 P2 0 S F P2 P6 P3 0 S F P3 P6 P4 0 S F P4 P6 P5 0 S F P5 P6
©Duane Szafron Stack Example - Maze Trace 2 P6 P10 0 S F P7 P10 P8 0 S F P8 P10 P9 0 S F P9 P10 0 S F Succes s!
©Duane Szafron Book Implementation of a Maze In the maze example of the textbook: –The walls of the maze are “widened” so they become positions in the maze. –This allows the maze to be represented in a textual format with # characters as “walls”. 0 S F ###### #s# # # ## # # # #### # # ## # # #f# ######
©Duane Szafron Maze Program 1 public static void main (String[ ] args) { // A Maze program. Maze maze; Position goal; Position current; Linear todo; maze = new Maze(args[0]); // Create a maze from a file goal = maze.finish(); todo = new StackList(); // A class that implements Stack current = maze.start(); code based on Bailey pg. 150
©Duane Szafron Maze Program 2 while (current != null && !current.equals(goal)) { maze.visit(current); pushUnvisitedNeighbor(todo, maze, current.north()); pushUnvisitedNeighbor(todo, maze, current.south()); pushUnvisitedNeighbor(todo, maze, current.west()); pushUnvisitedNeighbor(todo, maze, current.east()); if (todo.isEmpty()) current = null; else current = (Position) todo.remove(); } if (current == null) System.out.println(“No solution exists”); else System.out.println(“Solution found”); System.out.println(maze); } code based on Bailey pg. 150
©Duane Szafron Maze Program 3 public static void pushUnvisitedNeighbor (Linear todo, Maze maze, Position position) { // Post: If the given position is unvisited and is clear (not // a wall) in the given maze, it is pushed onto the given Stack. if (maze.isClear(position) && ! maze.isVisited(position)) todo.add(position); } code based on Bailey pg. 150
©Duane Szafron Vector-Based Stacks We can implement a Stack using a single Vector. This implementation is space and time efficient. It is also simple, so few mistakes can be made. However, the time for adding a particular element can vary, depending on whether the Vector must grow or not. Since the Vector will never shrink, the physical memory required is at least as large as the maximum Stack size, even if the Stack shrinks.
©Duane Szafron StackVector - State and Constructors public class StackVector implements Stack { /* An implementation of the Stack Interface that uses a single Vector to store the Stack elements. */ // Instance Variables // protected Vector data; public StackVector () { // post: initialize the Stack to be empty this.data = new Vector(); } public StackVector (int size) { /* post: initialize the Stack to be empty, but with the given initial capacity. */ this.data = new Vector(size); } code based on Bailey pg. 132
©Duane Szafron StackVector - Linear Interface 1 public void add (Object anObject) { // post: the object that is added will be popped next if // nothing else is added. Same operation as push this.data.addElement(anObject); } public Object remove (); // pre: stack is not empty // post: removes the most recently added object and // returns it. Same operation as pop Object result; result = this.data.elementAt(this.data.size() - 1); this.data.removeElementAt(this.data.size() - 1); return result; } code based on Bailey pg. 132
©Duane Szafron StackVector - Linear Interface 2 public Object peek (); // pre: stack is not empty // post: returns the next object to be removed, but // does in not remove it Assert.pre(!this.isEmpty(), “Stack is not empty”); return this.data.elementAt(this.data.size() - 1); } code based on Bailey pg. 132
©Duane Szafron StackVector - Stack Interface public void push (Object anObject); // post: the object that is added will be popped next if // nothing else is pushed. Same operation as add this.add(anObject); } public Object pop (); // pre: stack is not empty // post: removes the most recently pushed object and // returns it. Same operation as remove return this.remove(); } code based on Bailey pg. 133
©Duane Szafron StackVector - Store Interface public int size (); //post: returns the number of elements contained in the store. return this.data.size(); } public boolean isEmpty (); // post: returns the true iff store is empty. return this.size() == 0; } public void clear (); // post: clears the store so that it contains no elements. this.data.clear(); } code based on Bailey pg. 134
©Duane Szafron List-Based Stacks We can implement a Stack using a SinglyLinkedList. Recall that operations at the head of a SinglyLinkedList take constant time so this implementation is time efficient. As the Stack grows and shrinks, so does the list, unlike the Vector implementation that never shrinks. The time for adding a single element is always the same, unlike the Vector implementation There is extra link space required for each element. The implementation is simple, so few mistakes can be made.
©Duane Szafron StackList - State and Constructors public class StackList implements Stack { /* An implementation of the Stack Interface that uses a SinglyLinkedList to store the Stack elements. */ // Instance Variables // protected List data; public StackList() { // post: initialize the Stack to be empty this.data = new SinglyLinkedList(); } code based on Bailey pg. 134
©Duane Szafron StackList - Linear Interface 1 public void add (Object anObject) { // post: the object that is added will be popped next if // nothing else is added. Same operation as push this.data.addToHead(anObject); } public Object remove (); // pre: stack is not empty // post: removes the most recently added object and // returns it. Same operation as pop return this.data.removeFromHead(); } code based on Bailey pg. 134
©Duane Szafron StackList - Linear Interface 2 public Object peek (); // pre: stack is not empty // post: returns the next object to be removed, but does in // not remove it Assert.pre(!this.isEmpty(), “Stack is not empty”); return this.data.peek(); } code based on Bailey pg. 135
©Duane Szafron StackList - Stack Interface public void push (Object anObject); // post: the object that is added will be popped next if // nothing else is pushed. Same operation as add this.add(anObject); } public Object pop (); // pre: stack is not empty // post: removes the most recently pushed object and // returns it. Same operation as remove return this.remove(); } code based on Bailey pg. 135
©Duane Szafron StackList - Store Interface public int size (); //post: returns the number of elements contained in the store. return this.data.size(); } public boolean isEmpty (); // post: returns the true iff store is empty. return this.size() == 0; } public void clear (); // post: clears the store so that it contains no elements. this.data.clear(); } code based on Bailey pg. 135