STACK Stack ADT 2 A stack is an abstract data type based on the list data model All operations are performed at one end of the list called the top of the stack (TOS) “LIFO (for last-in first-out) list” is a synonym for stack Common operations: push(x) puts the element x on top of the stack pop removes the topmost element from the stack. Java Stack Interface 3 public interface Stack { public void push(Object x); public Object pop(); public Object peek(); public boolean isEmpty(); public void clear(); } From interface to implementation 4 Given that we want to support some interface, the designer still faces a choice What will be the best way to implement this interface for my expected type of use? Choice of implementation can reflect many considerations Major factors we think about Speed for typical use case Storage space required Array implementation of Stack 5 class ArrayStack implements Stack { max-1 private Object[] array; //Array that holds the Stack private int index = 0; //First empty slot in Stack index 4 public ArrayStack(int maxSize) 3 { array = new Object[maxSize]; } 2 1 public void push(Object x) { array[index++] = x; } 0 public Object pop() { return array[--index]; } public Object peek() { return array[index-1]; } public boolean isEmpty() { return index == 0; } public void clear() { index = 0; } } O(1) worstcase time for each operation Question: What can go wrong? …. What if maxSize is too small? Linked List Implementation of Stack 6 class ListStack implements Stack { private Node head = null; //Head of list that //holds the Stack public void push(Object x) { head = new Node(x, head); } public Object pop() { O(1) worst-case time for each operation (but constant is larger) Node temp = head; head = head.next; return temp.data; } public Object peek() { return head.data; } public boolean isEmpty() { return head == null; } public void clear() { head = null; } } head Note that array implementation can overflow, but the linked list version cannot Use of Stack 7 Infix to postfix conversion Postfix evaluation Function calls etc Infix to postfix 8 When an operand is read, output it When ( is read, push it When an operator is read: If TOS item has higher or equal precedence, repeatedly pop until TOS has an element of lower precedence or stack empty, then push the operator If the stack is empty or TOS item has lower precedence, just push it When ) is found, pop until we find the matching ( ( has the lowest precedence when in the stack but has the highest precedence when in the input When we reach the end of input, pop until the stack is empty Example 9 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: Output: Example 10 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( Output: Example 11 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( Output: 8 Example 12 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + Output: 8 Example 13 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + Output: 8 9 Example 14 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + * Output: 8 9 Example 15 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + * ( Output: 8 9 Example 16 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + * ( Output: 8 9 4 Example 17 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + * ( + Output: 8 9 4 Example 18 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + * ( + Output: 8 9 4 5 Example 19 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + * ( + * Output: 8 9 4 5 Example 20 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + * ( + * Output: 8 9 4 5 7 Example 21 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + * ( + Output: 8 9 4 5 7 * Example 22 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + * ( Output: 8 9 4 5 7 * + Example 23 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + * ( + Output: 8 9 4 5 7 * + Example 24 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + * ( + Output: 8 9 4 5 7 * + 6 Example 25 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + * ( Output: 8 9 4 5 7 * + 6 + Example 26 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + * Output: 8 9 4 5 7 * + 6 + Example 27 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( + Output: 8 9 4 5 7 * + 6 + * Example 28 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: ( Output: 8 9 4 5 7 * + 6 + * + Example 29 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: Output: 8 9 4 5 7 * + 6 + * + Example 30 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: + Output: 8 9 4 5 7 * + 6 + * + Example 31 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: + Output: 8 9 4 5 7 * + 6 + * + 3 Example 32 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: + * Output: 8 9 4 5 7 * + 6 + * + 3 Example 33 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: + * Output: 8 9 4 5 7 * + 6 + * + 3 5 Example 34 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: + Output: 8 9 4 5 7 * + 6 + * + 3 5 * Example 35 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: Output: 8 9 4 5 7 * + 6 + * + 3 5 * + Example 36 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: + Output: 8 9 4 5 7 * + 6 + * + 3 5 * + Example 37 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: + Output: 8 9 4 5 7 * + 6 + * + 3 5 * + 4 Example 38 (8 + 9 * (4 + 5 * 7 + 6)) + 3 * 5 + 4 Stack: Output: 8 9 4 5 7 * + 6 + * + 3 5 * + 4 + More Examples 39 Refer to the slides by Otávio Braga linked from the class website Postfix evaluation 40 Starting with an empty stack, we scan the postfix expression from left to right Each time we encounter an argument, we push it onto the stack When we encounter an operator, we pop the stack twice, remembering the operands popped We then apply the operator to the two popped values (with the second as the left operand) and push the result onto the stack Example 41 Evaluating 3 4 + 2 * Postfix to Expression Tree 42 A 2 * 2 A * B * - B 2 * + A B - / 1. Push A 2. Push 2 3. Pop 2 4. Pop A 5. Create tree_1 6. Push tree_1 7. Push 2 8. Push A 9. Pop A 10. Pop 2 11. Create tree_2 12. Push tree_2 13. Push B 14. Pop B 15. Pop tree_2 16. Create tree_3 17. Push tree_3 18. Pop tree_3 19. Pop tree_1 20. Create tree_4 21. Push tree_4 22. Push B 23. Push 2 24. Pop 2 25. Pop B 26. Create tree_5 27. Push tree_5 28. Pop tree_5 29. Pop tree_4 30. Create tree_6 31. Push tree_6 32. Push A 33. Push B 34. Pop B 35. Pop A 36. Create tree_7 37. Push tree_7 38. Pop tree_7 39. Pop tree_6 40. Create tree_8 41. Push tree_8 tree_8 tree_6 tree_4 tree_1 tree_5 tree_3 tree_2 tree_7 Evaluating expression tree 43 If at leaf node (operand node) return the operand’s value Otherwise: Evaluate the left sub-tree Evaluate the right sub-tree Combine the results from both sub-trees with the operator at root public static int eval(TreeCell root) { int left_result, right_result; if (root.datum is operand) return operand’s value; left_result = eval(root.left); right_result = eval(root.right); switch (root.datum) { case + : return left_result + right_result; case * : return left_result * right_result; : : } } Function calls 44 An important application of stacks is normally hidden from view A stack is used to allocate space in the computer’s memory to the variables belonging to the various functions of a program Example: a recursive factorial function Has a parameter n and a return value As fact calls itself recursively, different calls with different parameter are active at the same time A frame for each call is created and place on TOS When a given call return, its frame gets popped off public static int factorial(int 3) { int fact; if (n > 1) fact = factorial(2) * 3; else fact = 1; return fact; } public static int factorial(int 3) { int fact; if (n > 1) fact = factorial(2) * 3; else fact = 1; return fact; } public static int factorial(int 2) { int fact; if (n > 1) fact = factorial(1) * 2; else fact = 1; return fact; } public static int factorial(int 3) { int fact; if (n > 1) fact = factorial(2) * 3; else fact = 1; return fact; } public static int factorial(int 2) { int fact; if (n > 1) fact = factorial(1) * 2; else fact = 1; return fact; } public static int factorial(int 1) { int fact; if (n > 1) fact = factorial(n - 1) * n; else fact = 1; return fact; } public static int factorial(int 3) { int fact; if (n > 1) fact = factorial(2) * 3; else fact = 1; return fact; } public static int factorial(int 2) { int fact; if (n > 1) fact = factorial(1) * 2; else fact = 1; return fact; } public static int factorial(int 1) { int fact; if (n > 1) fact = factorial(n - 1) * n; else fact = 1; return 1; } public static int factorial(int 3) { int fact; if (n > 1) fact = factorial(2) * 3; else fact = 1; return fact; } public static int factorial(int 2) { int fact; if (n > 1) fact = 1 * 2; else fact = 1; return fact; } public static int factorial(int 1) { int fact; if (n > 1) fact = factorial(n - 1) * n; else fact = 1; return 1; } public static int factorial(int 3) { int fact; if (n > 1) fact = factorial(2) * 3; else fact = 1; return fact; } public static int factorial(int 2) { int fact; if (n > 1) fact = 1 * 2; else fact = 1; return 2; } public static int factorial(int 3) { int fact; if (n > 1) fact = 2 * 3; else fact = 1; return fact; } public static int factorial(int 2) { int fact; if (n > 1) fact = 1 * 2; else fact = 1; return 2; } public static int factorial(int 3) { int fact; if (n > 1) fact = 2 * 3; else fact = 1; return 6; }