1 Stacks and Queues Reading: Sections 3.6 and 3.7
2 Stack ADT - LIFO Collections: –Elements of some proper type T Operations: –Feature: Last In, First Out –void push(T t) –void pop() –T top() –bool empty() –unsigned int size() –constructor and destructor
3 Stack Model—LIFO Empty stack S –S.empty() is true –S.top() not defined –S.size() == 0 food chain stack
4 Stack Model—LIFO S.push(“mosquito”) –S.empty() is false –S.top() == “mosquito” –S.size() == 1 mosquito food chain stack
5 Stack Model—LIFO S.push(“fish”) –S.empty() is false –S.top() == “fish” –S.size() == 2 fish mosquito food chain stack
6 Stack Model—LIFO S.push(“raccoon”) –S.empty() is false –S.top() == “raccoon” –S.size() == 3 raccoon fish mosquito food chain stack
7 Stack Model—LIFO S.pop() –S.empty() is false –S.top() == “fish” –S.size() == 2 fish mosquito food chain stack
8 Implementations and Uses of Stack ADT Implementations –Any list implementation –list and vector C++ STL –Vector/List ADTs push_front()/pop_front() push_back()/pop_back() Uses –Depth first search / backtracking –Evaluating postfix expressions –Converting infix to postfix –Function calls (runtime stack) –Recursion
9 Depth First Search—Backtracking Problem –Discover a path from start to goal Solution –Start from Node start –Stop If node is goal –Go deep If there is an unvisited neighbor, go there –Backtrack Retreat along the path to find an unvisited neighbor, if cannot go deeper Outcome –If there is a path from start to goal, DFS finds one such path start goal
10 Depth First Search—Backtracking (2) Stack start goal 1 Push
11 Depth First Search—Backtracking (3) Stack start goal 2 1 Push
12 Depth First Search—Backtracking (4) Stack start goal Push
13 Depth First Search—Backtracking (5) Stack start goal Push
14 Depth First Search—Backtracking (6) Stack start goal Push
15 Depth First Search—Backtracking (7) Stack start goal Push Pop
16 Depth First Search—Backtracking (8) Stack start goal Push Pop
17 Depth First Search—Backtracking (9) Stack start goal 2 1 Push Pop
18 Depth First Search—Backtracking (10) Stack start goal 1 Push Pop
19 Depth First Search—Backtracking (11) Stack start goal 3 1 Push
20 Depth First Search—Backtracking (12) Stack start goal Push
21 Depth First Search—Backtracking (13) Stack start goal Push
22 DFS Implementation DFS() { stack S; // mark the start location as visited S.push(start); while (!S.empty()) { t = S.top(); if (t == goal) Success(S); if (// t has unvisited neighbors) { // choose an unvisited neighbor n // mark n visited; S.push(n); } else { BackTrack(S); } Failure(S); }
23 DFS Implementation (2) BackTrack(S) { while (!S.empty() && S.top() has no unvisited neighbors) { S.pop(); } Success(S) { // print success while (!S.empty()) { output(S.top()); S.pop(); } Failure(S) { // print failure while (!S.empty()) { S.pop(); }
24 Evaluating Postfix Expressions Infix expression –Operators in middle of operands –25 + x*(y – 5) Postfix expressions –operands precede operator –Z = 25 x y 5 - * + Tokens: atomics of expressions, either operator or operand Example: –25 + x*(y – 5) –Tokens: 25, +, x, *, (, y, -, 5, )
25 Evaluating Postfix Expressions (2) Evaluation algorithm: –Use stack of tokens –Repeat If operand, push onto stack If operator –pop operands off the stack –evaluate operator on operands –push result onto stack Until expression is read Return top of stack Most CPUs have hardware support for this algorithm Translation from infix to postfix also uses a stack (software)
26 Evaluating Postfix Expressions (3) Original expression: –1 + (2 + 3) * Evaluate: – * + 5 +
27 Evaluating Postfix Expressions (4) Input: * Push(1) 1
28 Evaluating Postfix Expressions (5) Input: * Push(2) 2 1
29 Evaluating Postfix Expressions (6) Input: * Push(3) 3 2 1
30 Evaluating Postfix Expressions (7) Input: + 4 * Pop() == 3 Pop() == 2 1
31 Evaluating Postfix Expressions (8) Input: + 4 * Push(2 + 3) 5 1
32 Evaluating Postfix Expressions (9) Input: 4 * Push(4) 4 5 1
33 Evaluating Postfix Expressions (10) Input: * Pop() == 4 Pop() == 5 1
34 Evaluating Postfix Expressions (11) Input: * Push(5 * 4) 20 1
35 Evaluating Postfix Expressions (12) Input: Pop() == 20 Pop() == 1
36 Evaluating Postfix Expressions (13) Input: Push(1 + 20) 21
37 Evaluating Postfix Expressions (14) Input: 5 + Push(5) 5 21
38 Evaluating Postfix Expressions (15) Input: + Pop() == 21 Pop() == 5
39 Evaluating Postfix Expressions (16) Input: + Push(21 + 5) 26
40 Evaluating Postfix Expressions (17) Input: Pop() == 26
41 Postfix Evaluation Implementation Evaluate(postfix expression) { // use stack of tokens; while(// expression is not empty) { t = next token; if (t is operand) { // push onto stack } else { // pop operands for t off stack // evaluate t on these operands // push result onto stack } // return top of stack }
42 Infix to Postfix Conversion Depends on operator precedence and associativity We present a limited version –+, -, *, /, (, ) –Assuming usual precedence and associativity High level idea –If input token is an operand, output directly –If input token is an operator, we need to compare the precedence of this operator with other neighboring operators, output the one with highest precedence –Parentheses need to handle differently ( has highest precedence when encountered in input compared to operators in stack, so we always push a ( ) is used to pop everything till ( in stack
43 Example Infix: –a + b * c + ( d * e + f ) * g Postfix –a b c * + d e * f + g * + a + b * c + ( d * e + f ) * g a b +
44 Example (cont’d) Infix: –a + b * c + ( d * e + f ) * g Postfix –a b c * + d e * f + g * + a + b * c + ( d * e + f ) * g a b c + *
45 Example (cont’d) Infix: –a + b * c + ( d * e + f ) * g Postfix –a b c * + d e * f + g * + a + b * c + ( d * e + f ) * g a b c * + +
46 Example (cont’d) Infix: –a + b * c + ( d * e + f ) * g Postfix –a b c * + d e * f + g * + a + b * c + ( d * e + f ) * g a b c * + d + (
47 Example (cont’d) Infix: –a + b * c + ( d * e + f ) * g Postfix –a b c * + d e * f + g * + a + b * c + ( d * e + f ) * g a b c * + d e + ( *
48 Example (cont’d) Infix: –a + b * c + ( d * e + f ) * g Postfix –a b c * + d e * f + g * + a + b * c + ( d * e + f ) * g a b c * + d e * f + ( +
49 Example (cont’d) Infix: –a + b * c + ( d * e + f ) * g Postfix –a b c * + d e * f + g * + a + b * c + ( d * e + f ) * g a b c * + d e * f + +
50 Example (cont’d) Infix: –a + b * c + ( d * e + f ) * g Postfix –a b c * + d e * f + g * + a + b * c + ( d * e + f ) * g a b c * + d e * f + g + *
51 Example (cont’d) Infix: –a + b * c + ( d * e + f ) * g Postfix –a b c * + d e * f + g * + a + b * c + ( d * e + f ) * g a b c * + d e * f + g * +
Infix to Postfix Conversion 52 void infix2postfix(const vector &infix) { stack s; for (I = 0; I < infix.size(); ++I) { if (infix[I] is operand) print infix[I]; else if (infix[I] is +, -, *, /, or ( ) { while (s.top() != ‘(‘ && s.top().precedence >= infix[I].precedence) { print s.top(); s.pop(); } s.push(infix[I]); } else if (infix[I] == ) ) { while (s.top() != ( ) { print s.top(); s.pop(); } s.pop(); // remove ( } while (!s.empty()) { print s.top(); s.pop(); } }
53 Runtime Stack Runtime environment –Static Executable code Global variables –Stack Push for each function call Pop for each function return Local variables –Heap Dynamically allocated memories new and delete static stack heap program memory
54 Recursion Order 1: function calls itself Order 2: f() calls g(), and g() calls f() Facilitated by stack
55 Reading Exercise How to use stack to –To check if brackets are balance? (Section 3.6.3)
56 Queue ADT - FIFO Collection –Elements of some proper type T Operations –Feature: First In, First Out –void push(T t) –void pop() –T front() –bool empty() –unsigned int size() –Constructors and destructors
57 Queue Model—FIFO Empty Q animal parade queue
58 Queue Model—FIFO Q.Push(“ant”) ant front back animal parade queue
59 Queue Model—FIFO Q.Push(“bee”) antbee front back animal parade queue
60 Queue Model—FIFO Q.Push(“cat”) antbeecat front back animal parade queue
61 Queue Model—FIFO Q.Push(“dog”) antbeecatdog front back animal parade queue
62 Queue Model—FIFO Q.Pop() beecatdog front back animal parade queue
63 Queue Model—FIFO Q.Pop() catdog front back animal parade queue
64 Queue Model—FIFO Q.Push(“eel”) Q.Pop() eel front back animal parade queue
65 Implementations and Uses of Queue ADT Implementations –Any list implementation push_front()/pop_back() push_back()/pop_front() Uses –Buffers –Breadth first search –Simulations –Producer-Consumer Problems
66 Breadth First Search Problem –Find a shortest path from start to goal Solution –Start from Node start –Visit All neighbors of the node –Stop If a neighbor is goal –Otherwise Visit neighbors two hops away –Repeat (Stop/Otherwise) Visiting neighbors N hops away start goal
67 Breadth First Search (2) Queue start goal 1 Push
68 Breadth First Search (3) Queue start goal Pop
69 Breadth First Search (4) Queue start goal 234 Push
70 Breadth First Search (5) Queue start goal Pop 34
71 Breadth First Search (6) Queue start goal 3456 Push
72 Breadth First Search (7) Queue start goal 456 Pop
73 Breadth First Search (8) Queue start goal Push
74 Breadth First Search (9) Queue start goal 5678 Pop
75 Breadth First Search (10) Queue start goal 678 Pop
76 Breadth First Search (11) Queue start goal 78 Pop
77 Breadth First Search (12) Queue start goal 789 Push
78 Breadth First Search (13) Queue start goal 89 Pop
79 Breadth First Search (14) Queue start goal 8910 Push
80 BFS Implementation BFS { queue Q; // mark the start location as visited Q.push(start); while (Q is not empty) { t = Q.front(); for (// each unvisited neighbor n of node t) { Q.push(n); if (n == goal) Success(S); } Q.pop(); } Failure(Q); }
81 Adaptor Class Adapts the public interface of another class Adaptee: the class being used Adaptor: the new class being defined –Uses protected object of the adaptee type –Uses the adaptee’s methods to define adaptor methods Stack and Queue implemented via adaptor classes
82 Stack Adaptor Requirements Stack –push() –pop() –top() –empty() –size() Can use List, Deque –Push(): push_back() –Pop(): pop_back()
83 Class Stack template class Stack { protected: Container c; public: void push(const T & x) { c.push_back(x); } void pop() { c.pop_back(); } T top() const { return c.back(); } int empty() const { return c.empty(); } unsigned int size() const { return c.size(); } void clear() { c.clear(); } }; Declaration –Stack > floatStack; –Stack > intStack; For STL stack container –template > class stack; –stack charStack;
84 Queue Adaptor Requirements Queue –push() –pop () –front() –empty() –size() Can use List, Deque –Push(): push_back() –Pop(): pop_front()
85 Class Queue template class Queue { protected: Container c; public: void push(const T & x) { c.push_back(x); } void pop() { c.pop_front(); } T front() const { return c.front(); } int empty() const { return c.empty(); } unsigned int size() const { return c.size(); } void clear() { c.clear(); } }; Declaration Queue > floatQueue; Queue > intQueue; For STL stack container template > class queue; queue charQueue;
86 Reading assignment Double-end queues –Section A problem to consider –A palindrome is a sequence of characters that can be same way forward and backward. –Can you think of a recursive algorithm to determine if an input string (line) is a palindrome or not. Character case is ignored (that is, low-case and upper-case characters are considered the same). The new line character is not part of the input string.