Stacks and Queues Andy Wang Data Structures, Algorithms, and Generic Programming

advertisement
Stacks and Queues
Andy Wang
Data Structures, Algorithms, and
Generic Programming
Abstract Data Type
A collection of data
A set of operations on the data or subsets
of the data
A set of axioms, or rules of behavior
governing the interaction of operators
Examples: stack, queue, list, vector,
deque, priority queue, table (map),
associative array, set, graph, digraph
Stack ADT
Collections:
Elements of some proper type T
Operations:
void push(T t)
void pop()
T top()
bool empty()
unsigned int size()
constructor and destructor
Stack ADT (2)
Axioms (for any stack S)
S.size, S.empty(), and S.push(t) are always
defined
S.pop() and S.top() are defined iff S.empty() is
false
S.empty(), S.size(), S.top() do not change S
S.empty() is true iff S.size() == 0
S.push(t) followed by S.pop() leaves S
unchanged
Stack ADT (3)
Axioms (for any stack S)
After S.push(t), S.top() returns t
S.push(t) increases S.size() by 1
S.pop() decreases S.size() by 1
Stack Model—LIFO
 Empty stack S
S.empty() is true
S.top() not defined
S.size() == 0
food chain stack
Stack Model—LIFO
 S.push(“mosquito”)
S.empty() is false
S.top() == “mosquito”
S.size() == 1
mosquito
food chain stack
Stack Model—LIFO
 S.push(“fish”)
S.empty() is false
S.top() == “fish”
S.size() == 2
fish
mosquito
food chain stack
Stack Model—LIFO
 S.push(“raccoon”)
S.empty() is false
S.top() == “raccoon”
S.size() == 3
raccoon
fish
mosquito
food chain stack
Stack Model—LIFO
 S.pop()
S.empty() is false
S.top() == “fish”
S.size() == 2
fish
mosquito
food chain stack
Derivable Behaviors (Theorems)
If (S.size() == n) is followed by k push
operations, then S.size() == n + k
If (S.size() == n) is followed by k pop
operations, then S.size == n – k (k <= n)
The last element of S pushed onto S is the
top of S
S.pop() removes the last element of S
pushed onto S
Uses of ADT Stack
Depth first search / backtracking
Evaluating postfix expressions
Converting infix to postfix
Function calls (runtime stack)
Recursion
Queue ADT
Collection
Elements of some proper type T
Operations
void push(T t)
void pop()
T front()
bool empty()
unsigned int size()
Constructors and destructors
Queue ADT
Axioms (for any Queue Q)
Q.size(), Q.empty(), Q.push(t) are always
defined
Q.pop() and Q.front() are defined iff Q.empty()
is false
Q.empty(), Q.size(), Q.front() do not change Q
Q.empty() is true iff Q.size() == 0
Suppose Q.size() == n, and the next element
pushed onto Q is t; then, after n elements have
been popped from Q, t = Q.front()
Queue ADT
Axioms (for any Queue Q)
Q.push(t) increases Q.size() by 1
Q.pop() decreases Q.size() by 1
If t = Q.front() then Q.pop() removes t from Q
Queue Model—FIFO
 Empty Q
animal parade queue
Queue Model—FIFO
 Q.Push(“ant”)
animal parade queue
ant
front
back
Queue Model—FIFO
 Q.Push(“bee”)
animal parade queue
ant
bee
front
back
Queue Model—FIFO
 Q.Push(“cat”)
animal parade queue
ant
bee
cat
front
back
Queue Model—FIFO
 Q.Push(“dog”)
animal parade queue
ant
bee
cat
dog
front
back
Queue Model—FIFO
 Q.Pop()
animal parade queue
bee
cat
dog
front
back
Queue Model—FIFO
 Q.Pop()
animal parade queue
cat
dog
front
back
Queue Model—FIFO
 Q.Push(“eel”)
 Q.Pop()
 Q.Pop()
animal parade queue
eel
front
back
Derivable Behaviors (Theorems)
If (Q.size() == n) is followed by k push
operations, then Q.size() == n + k
If (Q.size() == n) is followed by k pop
operations, then Q.size() == n – k (k <= n)
The first element pushed onto Q is the the
front of Q
Q.pop() removes the front element of Q
Uses of ADT Queue
Buffers
Breadth first search
Simulations
Depth First Search—Backtracking
 Problem
 Discover a path from start
to goal
 Solution
start 1
 Go deep
 If there is an unvisited
neighbor, go there
 Backtrack
 Retreat along the path to
find an unvisited
neighbor
 Outcome
 If there is a path from
start to goal, DFS finds
one such path
5
2
3
4
6
7
8
9
10
goal
11
12
Depth First Search—Backtracking (2)
 Stack
start 1
5
Push
1
2
3
4
6
7
8
9
10
goal
11
12
Depth First Search—Backtracking (3)
 Stack
start 1
5
Push
Push
2
1
2
3
4
6
7
8
9
10
goal
11
12
Depth First Search—Backtracking (4)
 Stack
start 1
5
Push
Push
Push
5
2
1
2
3
4
6
7
8
9
10
goal
11
12
Depth First Search—Backtracking (5)
 Stack
start 1
Push
Push
Push
Push
6
5
2
1
5
2
3
4
6
7
8
9
10
goal
11
12
Depth First Search—Backtracking (6)
 Stack
start 1
Push
Push
Push
Push
Push
9
6
5
2
1
5
2
3
4
6
7
8
9
10
goal
11
12
Depth First Search—Backtracking (7)
 Stack
start 1
Pop
Push
Push
Push
Push
6
5
2
1
5
2
3
4
6
7
8
9
10
goal
11
12
Depth First Search—Backtracking (8)
 Stack
start 1
2
3
4
6
7
8
9
10
Pop
5
Push
Push
Push
5
2
1
goal
11
12
Depth First Search—Backtracking (9)
 Stack
start 1
5
2
3
4
6
7
8
9
10
Pop
Push
Push
2
1
goal
11
12
Depth First Search—Backtracking (10)
 Stack
start 1
5
Pop
Push
1
2
3
4
6
7
8
9
10
goal
11
12
Depth First Search—Backtracking (11)
 Stack
start 1
5
Push
Push
3
1
2
3
4
6
7
8
9
10
goal
11
12
Depth First Search—Backtracking (12)
 Stack
start 1
5
Push
Push
Push
7
3
1
2
3
4
6
7
8
9
10
goal
11
12
Depth First Search—Backtracking (13)
 Stack
start 1
Push
Push
Push
Push
10
7
3
1
5
2
3
4
6
7
8
9
10
goal
11
12
DFS Implementation
DFS {
stack<location> S;
// mark the start location as visited
S.push(start);
while (S is not empty) {
t = S.top();
if (t == goal) Success(S);
if (// t has unvisited neighbors) {
// choose an unvisited neighbor
// mark n visited;
S.push(n);
} else {
BackTrack(S);
}
}
Failure(S);
}
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();
}
}
Breadth First Search
 Problem
Find a shortest path from start to goal
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
Breadth First Search (2)
 Queue
1
Push
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
Breadth First Search (3)
 Queue
Pop
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
Breadth First Search (4)
 Queue
2
3
4
Push
Push
Push
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
Breadth First Search (5)
 Queue
3
4
Pop
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
Breadth First Search (6)
 Queue
3
4
5
6
Push
Push
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
Breadth First Search (7)
 Queue
4
5
6
Pop
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
Breadth First Search (8)
 Queue
4
5
6
7
8
Push
Push
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
Breadth First Search (9)
 Queue
5
6
7
8
Pop
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
Breadth First Search (10)
 Queue
6
7
8
Pop
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
Breadth First Search (11)
 Queue
7
8
Pop
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
Breadth First Search (12)
 Queue
7
8
9
Push
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
Breadth First Search (13)
 Queue
8
9
Pop
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
Breadth First Search (14)
 Queue
8
9
10
Push
start 1
5
2
3
4
6
7
8
9
10
goal
11
12
BFS Implementation
BFS {
queue<location> Q;
// mark the start location as visited
Q.push(start);
while (Q is not empty) {
t = Q.front();
for (// each unvisited neighbor n) {
Q.push(n);
if (n == goal) Success(S);
}
Q.pop();
}
Failure(Q);
}
Evaluating Postfix Expressions
Postfix expressions: operands precede
operator
Tokens: atomics of expressions, either
operator or operand
Example:
z = 25 + x*(y – 5)
Tokens: z, =, 25, +, x, *, (, y, -, 5, )
Evaluating Postfix Expressions (2)
Evaluation algorithm:
Use stack of tokens
Repeat
If operand, push onto stack
If operator
• pop operands off stack
• evaluate operator on operands
• push result onto stack
Until expression is read
Return top of stack
Evaluating Postfix Expressions (3)
Most CPUs have hardware support for this
algorithm
Translation from infix to postfix also uses a
stack (software)
Evaluating Postfix Expressions (4)
Original expression: 1 + (2 + 3) * 4 + 5
Evaluate: 1 2 3 + 4 * + 5 +
Evaluating Postfix Expressions (5)
Input: 1 2 3 + 4 * + 5 +
Push(1)
1
Evaluating Postfix Expressions (6)
Input: 2 3 + 4 * + 5 +
Push(2)
2
1
Evaluating Postfix Expressions (7)
Input: 3 + 4 * + 5 +
Push(3)
3
2
1
Evaluating Postfix Expressions (8)
Input: + 4 * + 5 +
Pop() == 3
Pop() == 2
1
Evaluating Postfix Expressions (9)
Input: + 4 * + 5 +
Push(2 + 3)
5
1
Evaluating Postfix Expressions (10)
Input: 4 * + 5 +
Push(4)
4
5
1
Evaluating Postfix Expressions (11)
Input: * + 5 +
Pop() == 4
Pop() == 5
1
Evaluating Postfix Expressions (12)
Input: * + 5 +
Push(5 * 4)
20
1
Evaluating Postfix Expressions (13)
Input: + 5 +
Pop() == 20
Pop() == 1
Evaluating Postfix Expressions (14)
Input: + 5 +
Push(1 + 20)
21
Evaluating Postfix Expressions (15)
Input: 5 +
Push(5)
5
21
Evaluating Postfix Expressions (16)
Input: +
Pop() == 21
Pop() == 5
Evaluating Postfix Expressions (17)
Input: +
Push(21 + 5)
26
Evaluating Postfix Expressions (18)
Input:
Pop() == 26
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
}
Runtime Stack
Runtime environment
Static
heap
Executable code
Global variables
Stack
Push for each function call
Pop for each function return
Heap
Dynamic new and delete
stack
static
program memory
Recursion
Order 1: function calls itself
Order 2: f() calls g(), and g() calls f()
Facilitated by stack
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
Stack Adaptor Requirements
Stack
PushBack()
PopBack()
Back()
Empty()
Size()
Can use TDeque, TList, TVector
Queue Adaptor Requirements
Queue
PushBack()
PopFront()
Front()
Empty()
Size()
Can use TDeque, TList
Class CStack
template <typename T, class Container>
class CStack {
protected:
Container c;
public:
typedef T value_type;
void Push(const value_type& x) { c.PushBack(x); }
void Pop() { c.PopBack(); }
value_type Top() const { return c.Back(); }
int Empty() const { return c.Empty(); }
unsigned int Size() const { return c.Size(); }
void Clear() { c.Clear(); }
void Display(ostream& os, char ofc) const;
};
Class CStack (2)
template <typename T, class Container>
void CStack<T, Container>::Display(std::ostream& os, char ofc) const {
typename Container::Iterator I;
if (ofc == ‘\0’) {
for (I = c.Begin(); I != c.End(); ++I) {
os << *I;
}
} else {
for (I = c.Begin(); I != c.End(); ++I) {
os << *I << ofc;
}
}
}
template <typename T, class Container>
std::ostream& operator<<(std::ostream& os, const CStack<T, Container>& s) {
s.Display(os);
return os;
}
Declarations
CStack<float, TList<float> > floatStack;
CStack<int, TDeque<int> > intStack;
Class CQueue
template <typename T, class Container>
class CQueue {
protected:
Container c;
public:
typedef T value_type;
void Push(const value_type& x) { c.PushBack(x); }
void Pop() { c.PopFront(); }
value_type Front() const { return c.Front(); }
int Empty() const { return c.Empty(); }
unsigned int Size() const { return c.Size(); }
void Clear() { c.Clear(); }
void Display(ostream& os, char ofc) const;
};
Class CQueue (2)
template <typename T, class Container>
void CQueue<T, Container>::Display(std::ostream& os, char ofc) const {
typename Container::Iterator I;
if (ofc == ‘\0’) {
for (I = c.Begin(); I != c.End(); ++I) {
os << *I;
}
} else {
for (I = c.Begin(); I != c.End(); ++I) {
os << *I << ofc;
}
}
}
template <typename T, class Container>
std::ostream& operator<<(std::ostream& os, const CQueue<T, Container>& s) {
s.Display(os);
return os;
}
Example Usage
 Functionality Testing
fcstack.cpp
fcqueue.cpp
 Performance Testing
qrace.cpp
srace.cpp
dragstrp.h
timer.h
datetime.h
xran.h
Download