stacks - Gordon College

advertisement
Stacked
Deque
Gordon College
Adapted from Nyhoff, ADTs, Data Structures and Problem Solving with C++
1
Introduction to Stacks
• A stack is a last-in-first-out (LIFO) data
structure
• Adding an item
– Referred to as pushing it onto the stack
• Removing an item
– Referred to as
popping it from
the stack
2
A Stack
• Definition:
– An ordered collection of data items
– Can be accessed at only one end (the top)
• Operations:
– construct a stack (usually empty)
– check if it is empty
– Push: add an element to the top
– Top: retrieve the top element
– Pop: remove the top element
3
Stack STL specifics
value_type size_type
stack()
stack(const stack&)
stack& operator=(const stack&)
bool empty() const
size_type size() const
value_type& top()
const value_type& top() const
void push(const value_type&)
void pop()
(type constant within class)
(default constructor)
(copy constructor)
(assignment operator)
4
Example Program
• Consider a program to
do base conversion of
a number (from base ten to base two)
• Program to accomplish this
– Demonstrates push, pop, and top
5
#include <stack>
#include <iostream>
using namespace std;
void convert(int arg)
{
stack<int> binary;
while(arg>0)
{
binary.push(arg%2);
arg /= 2;
}
cout << endl;
while(!binary.empty())
{
cout << binary.top();
binary.pop();
}
cout << endl;
}
int main()
{
convert(101);
return 0;
}
6
Stack Programming
Application Example
• Use a stack ADT in a program that reads a
string, one character at a time and
determines whether the string contains
balanced parentheses (for each left
parentheses - there should be a right)
7
Deque
double-ended queue
(pronounced deck)
- elements are ordered following a
Quick Time™ an d a
d eco mp res sor
ar e n eed ed to s ee this pic ture .
strict linear sequence.
Properties
• Individual elements can be accessed by their position index.
• Iteration over the elements can be performed in any order.
• Elements can be efficiently added and removed from any of its ends
(either the beginning or the end of the sequence).
Like the vector in these ways - however not guaranteed to have all its
elements in contiguous storage locations
8
Deque
• For frequent insertion or removals of elements at positions other
than the beginning or the end, deques perform worse and have
less consistent iterators and references than lists.
• Like a vector:
– a sequence that supports random access to elements
– constant time insertion and removal of elements at the end of
the sequence
– linear time insertion and removal of elements in the middle.
• Not like a vector:
– constant time insertion and removal of elements at the
beginning of the sequence
– nothing like capacity() and reserve()
9
STL
Deque
Iterators:
begin Return iterator to beginning
end
Return iterator to end
rbegin Return reverse iterator
to reverse beginning
rend
Return reverse iterator
to reverse end
Capacity:
size
Return size
max_size Return maximum size
resize Change size
empty is empty?
Element access:
operator[] Access element
at
Access element
front
Access first element
back Access last element
Modifiers:
assign Assign container content
void assign ( InputIterator first, InputIterator last );
void assign ( size_type n, const T& u );
push_back Add element at the end
push_front Insert element at begin
pop_back Delete last element
pop_front Delete first element
insert Insert elements (iterator position)
erase Erase elements
swap Swap content
clear Clear content
10
STL Deque
Constructors
deque<int> first;
deque<int> second (4,100);
deque<int> third (second.begin(),second.end());
deque<int> fourth (third);
int myints[] = {16,2,77,29};
deque<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );
11
STL Deque
Comparable to vector methods:
void clear ( );
iterator erase ( iterator position );
iterator erase ( iterator first, iterator last );
reference front ( );
iterator insert ( iterator position, const T& x );
void insert ( iterator position, size_type n, const T& x );
void insert ( iterator position, InputIterator first, InputIterator last );
void pop_back ( );
void pop_front ( );
void push_back ( const T& x );
void push_front ( const T& x );
void swap ( deque<T,Allocator>& dqe );
12
STL Deque
Access methods:
const_reference at ( size_type n ) const;
reference at ( size_type n );
for (i=0; i<mydeque.size(); i++)
mydeque.at(i)=i;
cout << "mydeque contains:";
for (i=0; i<mydeque.size(); i++)
cout << " " << mydeque.at(i);
13
STL Deque Implementation
Design criteria:
1.
2.
3.
4.
Elements accessed by position
Elements efficiently added/removed from either end
Linear time add/removed from middle
No guarantee to contiguous elements
What sort of designs would work?
What is the better design and why?
14
Deque Implementation
• two common ways to implement:
– a modified dynamic array
– an array of arrays
a modified dynamic array
• can grow from both ends
• all the properties of a dynamic array:
– such as constant time random access
– good locality of reference
– inefficient insertion/removal in the middle
– constant time insertion/removal at both ends,
instead of just one end.
15
Deque Implementation
Common implementations for dynamic array:
• Using a circular buffer, and only resizing when the
buffer becomes completely full.
(back) OUT BACK
IN BACK
OUT FRONT (front)
IN FRONT
16
Deque Implementation
Common implementations for dynamic array:
• Allocating deque contents from the center of the
underlying array, and resizing the underlying array
when either end is reached. This approach may
require more frequent resizings and waste more
space, particularly when elements are only inserted at
one end.
Back
Front
17
Deque Implementation
•A dynamic array of fixed
arrays (blocks)
•Deque class keeps all
this information and
provides a uniform
access to the elements.
18
STL Stack Implementation
Design criteria:
1.
2.
Efficient access of top element
Elements efficiently added/removed from one end
What sort of design would work?
What is the better design and why?
19
Stack implementation possibilities
Selecting a Storage Structure for a Stack
• Model with an array
– Let position 0 be top of stack
• Problem … consider pushing and popping
– Requires much shifting
NOT EFFICIENT
20
Selecting Storage Structure
• A better approach is to let position 0 be the
bottom of the stack
• Thus our design will include
– An array to hold the stack elements
– An integer to indicate the top of the stack
21
Implementing Operations
• Constructor (static array)
– Compiler will handle
allocation of memory
• Empty
– Check if value of myTop == -1
• Push (if myArray not full)
– Increment myTop by 1
– Store value in myArray[myTop]
• Top
– If stack not empty, return myArray[myTop]
• Pop
– If array not empty, decrement myTop
22
Dynamic Array
to Store Stack Elements
• Issues regarding static arrays for stacks:
– Can run out of space if stack set too small
– Can waste space if stack set too large
• As before, we demonstrate a dynamic array
implementation to solve the problems
• What additional data members required?
Stack_ptr - pointer to dynamic stack
Capacity - capacity of stack
23
Dynamic Array
to Store Stack Elements
• Constructor stack A(5) must:
– Check that specified numElements > 0
– Set capacity to numElements
– Allocate an array pointed to by myArray with
capacity = myCapacity
– Set myTop to -1 if allocation goes OK
What additional methods are required for
this dynamic array approach?
24
Dynamic Array
to Store Stack Elements
• Class Destructor needed
– Avoids memory leak
– Deallocates array allocated by constructor
25
Dynamic Array
to Store Stack Elements
• Copy Constructor needed for
– Initializations
– Passing value parameter
– Returning a function value
– Creating a temporary storage value
• Provides for
deep copy
26
Dynamic Array
to Store Stack Elements
• Assignment operator
– Again, deep copy needed
– copies member-by-member, not just address
27
Further Considerations
• What if dynamic array initially allocated for
stack is too small?
– Terminate execution?
– Replace with larger array!
WE’VE SEEN THIS BEFORE!
•Stack
Creating
built a
onlarger
top ofarray
Vector (dynamic array)
– Allocate larger array
– Use loop to copy elements into new array
– Delete old array
– Point myArray variable at this new array
28
Further Considerations
• Another weakness – in the previous scenario
the type must be set with typedef mechanism
• This means we can only have one type of
Class Template
stackSolution:
in a program
– Would require completely different stack
declarations and implementations
29
Linked Stacks
built on top of lists
• Another alternative to allowing stacks to grow
as needed
• Linked list stack needs only one data
member
– Pointer myTop
– Nodes allocated (but not
directly part of stack class)
30
Implementing Linked Stack
Operations
• Constructor
– Simply assign null pointer to myTop
• Empty
– Check for myTop == null
• Push
– Insertion at beginning of list
• Top
– Return data to which myTop
points
31
Implementing Linked Stack Operations
• Pop
– Delete first node in the
linked list
ptr = myTop;
myTop = myTop->next;
delete ptr;
• Output
– Traverse the list
for (ptr = myTop;
ptr != 0; ptr = ptr->next)
out << ptr->data << endl;
32
Implementing Linked Stack Operations
• Destructor
– Must traverse list and deallocate nodes
– Note need to keep track of ptr->next before
calling delete ptr;
• Copy Constructor
– Traverse linked list,
copying each into
new node
– Attach new node
to copy
33
Implementing Linked Stack Operations
• Assignment operator
– Similar to copy constructor
– Must first rule out self assignment
– Must destroy list in stack being assigned a new
value
34
STL Stack Implementation
• implemented as container adaptors, which are
classes that use an encapsulated object of a
specific container class as its underlying container
The underlying structure of the stack
the standard container class templates vector, deque or list can be
used. By default - deque is used.
template < class T, class Container = deque<T> > class stack;
stack<int, vector<int> > binary;
stack<int> binary;
(deque is used)
35
STL Stack Implementation
Constructors for Stack
deque<int> mydeque (3,100); // deque with 3 elements
vector<int> myvector (2,200); // vector with 2 elements
stack<int> first;
// empty stack
stack<int> second (mydeque); // stack initialized to copy of deque
stack<int,vector<int> > third; // empty stack using vector
stack<int,vector<int> > fourth (myvector);
36
Application of Stacks
Consider events when a function begins
execution
• Activation record (or stack frame) is created
• Stores the current environment for that
function.
• Contents:
37
Run-time Stack (call stack)
• Functions may call other functions
– interrupt their own execution
• Must store the activation records to be
recovered
– system then reset when first function resumes
execution
• This algorithm must have LIFO behavior
• Structure used is the run-time stack
38
Use of Run-time Stack
When a function is called …
• Copy of activation record pushed onto runtime stack
• Arguments copied into parameter spaces
• Control transferred to starting address of
body of function
39
Use of Run-time Stack
When function terminates
• Run-time stack popped
– Removes activation record of terminated function
– exposes activation record of previously executing
function
• Activation record used to restore environment of
interrupted function
• Interrupted function resumes execution
40
Call Stack for Motorola 68000 processor
int CallingFunction(int x)
{
int y;
CalledFunction(1,2);
return (5);
}
void CalledFunction(int param1, int param2)
{
int local1, local2;
local1 = param2;
}
41
Application of Stacks
Consider the arithmetic statement in the assignment
statement:
x=a*b+c
Compiler must generate
machine instructions
1. LOAD
a
Note: this is "infix" notation
The operators are
2. MULT
b
between the operands
3. ADD
c
4. STORE
x
42
RPN or Postfix Notation
• Most compilers convert an expression in
Conversion
from infix
to postfix:
infix notation
to postfix
Rule 1: Scan the infix expression from left to right.
– the operators
areoperand
writtenasafter
operands
Immediately
record an
soonthe
as you
identify it
the expression
• inSo
a * b + c becomes a b * c +
Rule 2: Record an operator as soon as you identify its
• operands
Advantage:
– expressions can be written without parentheses
Infix
(a+b)*c
(a*b+c)/d+e
Postfix
ab+c*
ab*c+d/e+
43
Postfix and Prefix Examples
INFIX
A+B
A*B+C
A * (B + C)
A - (B - (C - D))
A-B-C-D
RPN (POSTFIX)
A
A
A
A
A
B +
B * C +
B C + *
B C D--B-C-D-
PREFIX
+ A B
+ * A B C
* A + B C
-A-B-C D
---A B C D
Prefix : Operators come
before the operands
44
Evaluating RPN Expressions
"By hand" (Underlining technique):
1. Scan the expression from left to right to find an operator.
2. Locate ("underline") the last two preceding operands
and combine them using this operator.
3. Repeat until the end of the expression is reached.
Example:
2
 2
 2
 2
 2
 2
3
3
7
7
7
7
4 + 5 6
4 + 5 6
5 6 - 5 6 - -1 - *
-1 - *
- - *
- - *
*
*
 2 8 *  2 8 *  16
45
Evaluating RPN Expressions
By using a stack algorithm
1. Initialize an empty stack
2. Repeat the following until the end of the
expression is encountered
a)
b)
Get the next token (const, var, operator) in the
expression
Operand – push onto stack
Note: if only 1 value on
stack, this is an invalid
Operator – do the following
i.
ii.
iii.
3.
Pop 2 values from stack
Apply operator to the two values
Push resulting value back onto stack
RPN expression
When end of expression encountered, value of
expression is the (only) number left in stack
46
Evaluation
of Postfix
• Note the
changing
status of the
stack
47
Converting Infix to RPN
By hand: Represent infix expression as an expression tree:
A * B + C
A * (B + C)
*
+
*
A
((A + B) * C) / (D - E)
A
C
B
x D y
x
-
*
+
B
D
/
+
C
A
C
D
E
B
y
48
/
Traverse the tree in Left-Right-Parent
order (postorder) to get RPN:
-
*
A B+C*DE- /
+
Traverse tree in Parent-Left-Right
order (preorder) to get prefix:
A
/
B
-
*
/ * + A BC- D E
+
Traverse tree in Left-Parent-Right
order (inorder) to get infix:
— must insert ()'s
E
D
C
E
D
C
/
A
B
+
( ((A + B) * C)/(D - E) )
A
-
*
C
E
D
B
49
Another RPN Conversion Method
By hand: "Fully parenthesize-move-erase" method:
1. Fully parenthesize the expression.
2. Replace each right parenthesis by the
corresponding operator.
3. Erase all left parentheses.
Examples:
A * B + C
 ((A * B) + C)
 ((A B * C +
 A B * C +
A * (B + C)
 (A * (B + C) )
 (A (B C + *
 A B C + *
50
Stack Algorithm
convert from infix to postfix
1. Initialize an empty stack of operators
2. While no error && !end of expression
a) Get next input "token" from infix expression
b) If token is …
const, var, arith operator,
left or right paren
i. "(" : push onto stack
ii. ")" : pop and display stack elements until
"(" occurs, do not display it
51
Stack Algorithm
3.
Note: Left parenthesis in
stack has lower priority
than operators
iii. operator
if operator has higher priority than top of stack
push token onto stack
else
pop and display top of stack
repeat comparison of token with top of stack
iv. operand display it
When end of infix reached, pop and display stack
items until empty
52
Download