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
1
2 3 4
5 6 87
9 10 1211
start
goal
10
Depth First Search—Backtracking (2)
• Stack
1
2 3 4
5 6 87
9 10 1211
start
goal
1Push
11
Depth First Search—Backtracking (3)
• Stack
1
2 3 4
5 6 87
9 10 1211
start
goal
2
1Push
Push
12
Depth First Search—Backtracking (4)
• Stack
1
2 3 4
5 6 87
9 10 1211
start
goal
5
2
1Push
Push
Push
13
Depth First Search—Backtracking (5)
• Stack
1
2 3 4
5 6 87
9 10 1211
start
goal
6
5
2
1Push
Push
Push
Push
14
Depth First Search—Backtracking (6)
• Stack
1
2 3 4
5 6 87
9 10 1211
start
goal
9
6
5
2
1Push
Push
Push
Push
Push
15
Depth First Search—Backtracking (7)
• Stack
1
2 3 4
5 6 87
9 10 1211
start
goal
6
5
2
1Push
Push
Push
Push
Pop
16
Depth First Search—Backtracking (8)
• Stack
1
2 3 4
5 6 87
9 10 1211
start
goal
5
2
1Push
Push
Push
Pop
17
Depth First Search—Backtracking (9)
• Stack
1
2 3 4
5 6 87
9 10 1211
start
goal
2
1Push
Push
Pop
18
Depth First Search—Backtracking (10)
• Stack
1
2 3 4
5 6 87
9 10 1211
start
goal1Push
Pop
19
Depth First Search—Backtracking (11)
• Stack
1
2 3 4
5 6 87
9 10 1211
start
goal
3
1Push
Push
20
Depth First Search—Backtracking (12)
• Stack
1
2 3 4
5 6 87
9 10 1211
start
goal
7
3
1Push
Push
Push
21
Depth First Search—Backtracking (13)
• Stack
1
2 3 4
5 6 87
9 10 1211
start
goal
10
7
3
1Push
Push
Push
Push
22
DFS Implementation
DFS() {stack<location> S;
// mark the start location as visitedS.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 successwhile (!S.empty()) {
output(S.top());S.pop();
}}
Failure(S) {// print failurewhile (!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) * 4 + 5
• Evaluate: – 1 2 3 + 4 * + 5 +
27
Evaluating Postfix Expressions (4)
• Input: 1 2 3 + 4 * + 5 +• Push(1)
1
28
Evaluating Postfix Expressions (5)
• Input: 2 3 + 4 * + 5 +• Push(2)
2
1
29
Evaluating Postfix Expressions (6)
• Input: 3 + 4 * + 5 +• Push(3)
3
2
1
30
Evaluating Postfix Expressions (7)
• Input: + 4 * + 5 +• Pop() == 3• Pop() == 2
1
31
Evaluating Postfix Expressions (8)
• Input: + 4 * + 5 +• Push(2 + 3)
5
1
32
Evaluating Postfix Expressions (9)
• Input: 4 * + 5 +• Push(4)
4
5
1
33
Evaluating Postfix Expressions (10)
• Input: * + 5 +• Pop() == 4• Pop() == 5
1
34
Evaluating Postfix Expressions (11)
• Input: * + 5 +• Push(5 * 4)
20
1
35
Evaluating Postfix Expressions (12)
• Input: + 5 +• Pop() == 20• Pop() == 1
36
Evaluating Postfix Expressions (13)
• Input: + 5 +• 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<token> &infix) { stack<token> 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”)
ant bee
front
back
animal parade queue
60
Queue Model—FIFO
• Q.Push(“cat”)
ant bee cat
front
back
animal parade queue
61
Queue Model—FIFO
• Q.Push(“dog”)
ant bee cat dog
front
back
animal parade queue
62
Queue Model—FIFO
• Q.Pop()
bee cat dog
front
back
animal parade queue
63
Queue Model—FIFO
• Q.Pop()
cat dog
front
back
animal parade queue
64
Queue Model—FIFO
• Q.Push(“eel”)• Q.Pop()• 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
1
2 3 4
5 6 87
9 10 1211
start
goal
67
Breadth First Search (2)
• Queue
1
2 3 4
5 6 87
9 10 1211
start
goal
1
Push
68
Breadth First Search (3)
• Queue
1
2 3 4
5 6 87
9 10 1211
start
goal
Pop
69
Breadth First Search (4)
• Queue
1
2 3 4
5 6 87
9 10 1211
start
goal
2 3 4
Push Push Push
70
Breadth First Search (5)
• Queue
1
2 3 4
5 6 87
9 10 1211
start
goal
Pop
3 4
71
Breadth First Search (6)
• Queue
1
2 3 4
5 6 87
9 10 1211
start
goal
3 4 5 6
Push Push
72
Breadth First Search (7)
• Queue
1
2 3 4
5 6 87
9 10 1211
start
goal
4 5 6
Pop
73
Breadth First Search (8)
• Queue
1
2 3 4
5 6 87
9 10 1211
start
goal
4 5 6 7 8
Push Push
74
Breadth First Search (9)
• Queue
1
2 3 4
5 6 87
9 10 1211
start
goal
5 6 7 8
Pop
75
Breadth First Search (10)
• Queue
1
2 3 4
5 6 87
9 10 1211
start
goal
6 7 8
Pop
76
Breadth First Search (11)
• Queue
1
2 3 4
5 6 87
9 10 1211
start
goal
7 8
Pop
77
Breadth First Search (12)
• Queue
1
2 3 4
5 6 87
9 10 1211
start
goal
7 8 9
Push
78
Breadth First Search (13)
• Queue
1
2 3 4
5 6 87
9 10 1211
start
goal
8 9
Pop
79
Breadth First Search (14)
• Queue
1
2 3 4
5 6 87
9 10 1211
start
goal
8 9 10
Push
80
BFS Implementation
BFS {queue<location> Q;
// mark the start location as visitedQ.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 Stacktemplate <typename T, class Container>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<float, List<float> > floatStack;– Stack<int, Vector<int> > intStack;
• For STL stack container– template <typename T, typename Container = deque<T> > class stack;– stack<char> charStack;
84
Queue Adaptor Requirements
• Queue– push()– pop ()– front()– empty()– size()
• Can use List, Deque– Push(): push_back()– Pop(): pop_front()
85
Class Queuetemplate <typename T, class Container>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(); }
};
• DeclarationQueue<float, List<float> > floatQueue;Queue<int, List<int> > intQueue;
• For STL stack containertemplate <typename T, typename Container = deque<T> > class queue;queue<char> charQueue;
86
Reading assignment
• Double-end queues– Section 3.7.2
• 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.