4. Stacks

advertisement
4. Stacks
Introduction
Consider the 4 problems on pp. 170-1
(1) Model the discard pile
in a card game
(2) Model a railroad
switching yard
(3) Parentheses checker
(4) Calculate and display basetwo representation
26 = ???????2
1
In the last problem:
Remainders are generated in right-to-left order. We need to
"stack" them up, then print them out from top to bottom.
In these problems we need a
"last-discarded-first-removed,"
"last-pushed-onto-first-removed,"
"last-stored-first-removed, "
"last-generated-first-displayed"
structured data type.
In summary ... a _____________________________structure.
2
Stack as an ADT
A stack is:
Basic operations
1. _________________________________
2. Check if stack _______________
3. _____________an element ______________ of the stack
4. _____________ the _____________ of the stack
5. _____________ the _____________ of the stack
Terminology is from spring-loaded
stack of plates in a cafeteria:
Adding a plate pushes those below it
down in the stack
Removing a plate pops those below it
up one position.
3
Example use of Stack
BASE-CONVERSION ALGORITHM
(See p. 171-2)
/* This algorithm displays the base-2 representation
of a base-10 number.
Receive:
a positive integer number
Output:
the base-two representation of number.
------------------------------------------------------------------*/
1. Create an empty stack to hold the remainders.
2. While number ≠ 0:
a. Calculate the remainder that results when
number is divided by 2.
b. Push remainder onto the stack of remainders.
c. Replace number by the integer quotient of
number divided by 2.
4
3. While the stack of remainders is not
empty:
a. Retrieve and remove the remainder
from the top of the stack of
remainders.
b. Display remainder.
5
/* Program that uses a stack to convert the base-ten
* representation of a positive integer to base two.
*
* Input: A positive integer
* Output: Base-two representation of the number
***************************************************/
__________________ // our own -- <stack> for STL version
#include <iostream>
using namespace std;
int main()
{
unsigned number,
remainder;
// the number to be converted
// remainder when number is
//
divided by 2
_______________________________________________________
char response;
// user response
6
do
{
cout << "Enter positive integer to convert: ";
cin >> number;
while (number != 0)
{
remainder = number % 2;
____________________________________;
number /= 2;
}
cout << "Base-two representation: ";
while (_________________________________)
{
____________________________________;
____________________________________;
cout << remainder;
}
cout << "\nMore (Y or N)? "; cin >> response;
}
while (response == 'Y' || response == 'y');
)
7
Building a Stack Class
Two steps:
1. ____________the class; and
2. ____________the class.
1. Design:
__________________________needed to manipulate "real-world"
objects being modeled by class.
Operations are described:
_______________________________________________.
In a manner independent of any specific representation of object
(because we have no idea of what data members will be available).
8
Stack Operations:
Construction:
Empty operation:
Push operation:
Top operation:
Pop operation:
Initializes an empty stack.
Determines if stack contains any values
Modifies a stack by adding a value to top of
stack
Retrieves the value at the top of the stack
Modifies a stack by removing the top value
of the stack
To help with debugging, add early on:
Output:
Displays all the elements stored in the stack.
9
2. Implementing a Stack Class
Define data members: consider storage structure(s)
Attempt #1: Use an array with the top of the stack at position 0.
e.g., Push 75, Push 89, Push 64, Pop
Push 75
0
1
2
3
4
0
1
2
3
4
Push 64
Push 89
0
1
2
3
4
0
1
2
3
4
Pop
0
1
2
3
4
+ features: ________________________________________________________
– features: ________________________________________________________
10
Implementing Stack Class — Refined
Instead of modeling a stack of plates, model a stack of books (or a discard pile in a
card game.)
Keep the bottom of stack at position 0. Maintain a "pointer" myTop to the top
of the stack.
Push 75
Push 89
Push 64
Pop
4
3
2
1
0
myTop = __
4
3
2
1
0
myTop = __
4
3
2
1
0
myTop = __
4
3
2
1
0
myTop = __
Note: _______________________________________
4
3
2
1
0
myTop = __
11
Stack's Data Members
Provide:
• An ________ data member to hold the____________________.
• An ________ data member to indicate the ________________.
Problems: We need an array declaration of the form
ArrayElementType myArray[ARRAYCAPACITY];
— What type should be used?
Solution (for now): Use the typedef mechanism:
______________________________
// put this before the class declaration
— What about the capacity?
______________________________
// put this before the class declaration
Now we can declare the array data member in the private section:
_______________________________________
12
Notes:
1. typedef makes StackElement a synonym for int
2 Want a stack of reals, or characters, or . . . ? Change the typedef
typedef double StackElementType;
or
typedef char StackElementType;
or . . .
When class library is recompiled, array elements will be double or char or . . .
3. An alternative to using and changing a typedef: Write a ____________
to build a Stack class whose element type is left unspecified.
The element type is __________as a special kind of _______________
at compile time.
This is the approach used in the Standard Template Library (STL) and in
most of the other C++ libraries.
13
4. The typedef and declaration of STACK_CAPACITY outside the class
declaration makes them:
 easy to find when they need changing
 accessible throughout the class and in any file that #includes Stack.h
 without qualification
If we put typedef of StackElement and declaration of the constant
STACK_CAPACITY in public section of the class declaration, they can be
accessed outside the class, but require qualification:
____________StackElement
____________STACK_CAPACITY
5. If we were to make STACK_CAPACITY a data member, we would probably
make it a _________ data member:
_________ const int STACK_CAPACITY = 128;
This makes it a property of the class usable by all class objects, but they do not
have their own copies of STACK_CAPACITY.
14
//Stack.h
/* Stack.h provides a Stack class.
*
* Basic operations:
*
Constructor: Constructs an empty stack
*
empty:
Checks if a stack is empty
*
push:
Modifies a stack by adding a value at the top
*
top:
Accesses the top stack value; leaves stack
*
unchanged
*
pop:
Modifies a stack by removing the value at the
*
top
*
display:
Displays all the stack elements
* Class Invariant:
*
1. The stack elements (if any) are stored in positions
*
0, 1, . . ., myTop of myArray.
*
2. -1 <= myTop < STACK_CAPACITY
------------------------------------------------------------*/
15
#ifndef STACK
#define STACK
const int STACK_CAPACITY = 128;
typedef int StackElement;
class Stack
{
/***** Function Members *****/
public:
. . .
/***** Data Members *****/
private:
}; // end of class declaration
. . .
#endif
16
Stack's Function Members
Constructor:
class Stack
{
public:
/*--- Constructor --Precondition: A stack has been declared.
Postcondition: Stack has been constructed
as an empty stack.
*/
_______________________
...
} // end of class declaration
Simple
enough to
inline?
___________________________________________
17
A declaration
Stack s;
will construct s as follows:
s
0
1
2
3
4
. . .
127
18
empty:
Receives
Returns:
Stack containing it as a function member (perhaps implicitly)
True if stack is empty, false otherwise.
Member function? _______
Const function? (Shouldn't alter data members)? _______
Simple enough to inline? ______
class Stack
{
public:
. . .
/* --- Is the Stack empty? --* Returns: true if the Stack containing this
*
function is empty and false otherwise
***************************************************/
______________________________
. . .
};// end of class declaration
____________________________________________
{ return (myTop == -1); }
19
Test driver:
#include <iostream>
#include <iomanip>
using namespace std;
#include "Stack.h"
int main()
{
Stack s;
cout << boolalpha << "s empty? "
<< s.empty() << endl;
}
Output:
s empty? ___________________
or if boolalpha omitted or not implemented:
s empty? ___________________
20
push:
Receives
Returns:
Stack containing it as a function member (perhaps implicitly)
Value to be added to stack
Modified stack (perhaps implicitly)
Member function? _______
Const function? _______
Simple enough to inline? _______
Add to class declaration:
/* --- Add a value to the stack --*
* Receive: A value to be added to a Stack
* Postcondition: Value is added at top of stack
*
provided there's space
* Output: "Stack full" message if no space
*************************************************/
_____________________________________________________
21
Add to Stack.cpp:
void Stack::push(_____________________________________)
{
_________________________________________
{
//Preserve stack invariant
}
// or simply,_______________________ = value;
else
cerr <<
"*** Stack full -- can't add new value ***\n"
"Must increase value of STACK_CAPACITY in Stack.h\n";
}
22
Add at bottom of driver:
for (int i = 1; i <= 128; i++) s.push(i);
cout << "Stack should now be full\n";
s.push(129);
Output:
s empty? true
Stack should now be full
*** Stack is full -- can't add new value ***
Must increase value of STACK_CAPACITY in Stack.h
23
Output: So we can test our operations.
Receives:
Output:
Stack containing it as a function member (perhaps implicitly)
an ostream
Contents of Stack, from the top down.
Member function?______ Const function?_____ Simple enough to inline?______
Add to class declaration:
/* --- Display values stored in the stack --*
* Receive: The ostream out
* Output: Stack's contents, from top down, to out
***************************************************/
_______________________________________________
Add to Stack.cpp
______ void ________display(ostream & out)
{
for (int i = myTop; i >= 0; i--)
out << myArray[i] << endl;
}
24
Modify driver:
/*
for (int i = 1; i <= 128; i++) s.push(i);
cout << "Stack should now be full\n";
s.push(129);
*/
for (int i = 1; i <= 4; i++) s.push(2*i);
cout << "Stack contents:\n";
s.display(cout);
cout << "s empty? " << s.empty() << endl;
Output:
s empty? true
Stack contents:
8
6
4
2
s empty? false
25
top:
Receives:
Returns:
Output:
Stack containing it as a function member (perhaps implicitly)
Value at the top of the stack
Error message if stack is empty
Member function? _______
Const function? _______
Simple enough to inline?_______
Add to class declaration:
/* --- Return value at top of the stack --* Return: value at the top of nonempty Stack
* Output: "Stack empty" message if stack empty
***************************************************/
_________________________________________
26
Add to Stack.cpp:
StackElement Stack::top() const
{
if (myTop >= 0)
return (myArray[myTop]);
else
{
cerr << "*** Stack is empty "
" -- returning garbage ***\n";
return myArray[STACK_CAPACITY-1];
}
Output:
}
Stack contents:
8
Add to driver at bottom:
6
cout << "Top value: " << s.top()
4
<< endl;
2
s empty? false
Top value: 8 27
pop:
Receives
Returns:
Output:
Stack containing it as a function member (perhaps implicitly)
Stack with top element removed (perhaps implicitly)
Error message if stack is empty.
Member function?_____ Const function?______ Simple enough to inline?______
class Stack
. . .
/* --- Remove value at top of the stack --* Postcondition: Top value of stack (if any) has
*
been removed.
* Output: "Stack-empty" message if stack is empty.
**************************************************/
____________________________
. . .
}; // end of class declaration
28
_______ void _______ pop() _______
{
if (myTop >= 0)
// Preserve stack invariant
myTop--;
else
cerr << "*** Stack is empty -- "
"can't remove a value ***\n";
}
Output:
Add to driver at bottom:
Stack contents:
8
6
4
2
s empty? false
Top value: 8
Popping 8
Popping 6
Popping 4
Popping 2
s empty? true 29
while (!s.empty())
{
cout << "Popping " << s.top()
<< endl;
s.pop();
}
cout << "s empty? " << s.empty()
<< endl;
Application of Stacks:Run-time Stack
Whenever a function begins execution (i.e., is activated), an
activation record (or stack frame) is created to store the
current environment for that function. Its contents include:
parameters
caller's state information (saved)
(e.g., contents of registers, return address)
local variables
temporary storage
What kind of data structure should be used to store these so
that they can be recovered and the system reset when the
function resumes execution?
30
Problem: FunctionA can call FunctionB
FunctionB can call FunctionC
...
When a function calls another function, it interrupts its own
execution and needs to be able to resume its execution in the same
state it was in when it was interrupted.
When FunctionC finishes, control should return to FunctionB.
When FunctionB finishes, control should return to FunctionA.
So, the order of returns from a function is the reverse of function
invocations; that is, ________behavior.
 Use a _________to store the activation records. Since it is
manipulated at run-time, it is called the ____________________
31
What happens when a function is called?
1. ________ copy of its activation record _______________________
2. Copy its arguments into the parameter spaces
3. Transfer control to the address of the function's body
The ______ activation record in the run-time stack is always
that of the function ____________________.
What happens when a function terminates?
1. _________ activation record of terminated function from the
run-time stack
2. Use new top activation record to ______________________
___________________________________________________
execution of the interrupted function.
32
Examples
Trace run-time stack for the
following:
. . .
int main()
{ . . .
f2(...);
f3(...);
}
void f1(...) {. . .}
void f2(...) {...
f1(...); ...}
void f3(...) {...
f2(...); ...}
int factorial(int n)
{
if (n < 2)
return 1;
else
return n * factorial(n-1);
}
What happens to the run-time stack when the
following statement executes?
int answer = factorial(4);
This pushing and popping of the run-time stack is the real
overhead associated with function calls that inlining avoids by
replacing the function call with the body of the function.
33
Application of Stacks: RPN
1. What is RPN (Reverse Polish Notation)?
A notation for arithmetic expressions in which operators are
written _____________ the operands. Expressions can be written
without using ____________________.
Developed by Polish logician, Jan Lukasiewics, in 1950's
Infix notation:
Postfix " (RPN):
Prefix " :
operators written _________ the operands
operators written _________ the operands
operators written _________ the operands
Examples:
INFIX
RPN (POSTFIX)
A + B
__________________
A * B + C
__________________
A * (B + C)
__________________
A - (B - (C - D)) __________________
A - B - C - D
__________________
PREFIX
____________________
____________________
____________________
____________________
____________________
34
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 4 + 5 6
3 4 + 5 6
__ 5 6 - 7 5 6 - 7 ____ - *
7 -1 - *
- - *
- - *
*
*
 2 __ *  2 8 *  ___
35
Stack Algorithm:
(p.195)
Receive: An RPN expression.
Return: A stack whose top element is the value of RPN expression
(unless an error occurred).
1. Initialize an empty stack.
2. Repeat the following until the end of the expression is
encountered:
a. Get next token (constant, variable, arithmetic operator) in
the RPN expression.
b. If token is an operand, push it onto the stack.
If it is an operator, then:
(i) Pop top two values from the stack. If stack
does not contain two items, signal error due to a
malformed RPN and terminate evaluation.
(ii) Apply the operator to these two values.
(iii) Push the resulting value back onto the stack.
3. When the end of expression encountered, its value is on top
of the stack (and, in fact, must be the only value in the stack).
Generate code:
LOAD
operand1
op
operand2
STORE TEMP#:
Push TEMP#
36
Sample RPN Evaluation (p. 196)
Example: 2 3 4 + 5 6 - - *
Push
Push
Push
Read
2
3
4
+
Pop 4, Pop 3, ___________
Push
Push
Push
Read
Push
Read
Push
Read
Push
7
5
6
Pop 6, Pop 5, 5___________
- 6 = -1
-1
Pop -1, Pop 7, 7__________
- -1 = 8
8
*
2 * 8 = 16
Pop 8, Pop 2, ___________
16
2
-1
7
2
8
2
16
37
Unary minus causes problems
Example:
5 3 - -
5 3 - -


OR
5 3 - 

Use a different symbol:
5 3 ~ -
5 3 - ~
38
Converting Infix to RPN
By hand: Represent infix expression as an expression tree:
A * B + C
A * (B + C)
((A + B) * C) / (D - E)
39
/
Traverse the tree in Left-Right-Parent
order (postorder) to get _________:
+
Traverse tree in Parent-Left-Right
order (preorder) to get ____________:
-
*
A
/
B
-
*
+
Traverse tree in Left-Parent-Right
order (inorder) to get ___________
— must insert ()'s
E
D
C
E
D
C
/
A
B
-
*
+
A
C
B
E
D
40
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)
 _____________
 _____________
 _____________
Exercise:
((A + B) * C) / (D - E)
41
Stack Algorithm:
(p.199)
1. Initialize an empty stack of operators.
2. While no error has occurred and end of infix expression not reached
a. Get next token in the infix expression.
b. If token is
(i) a left parenthesis:
(ii) a right parenthesis:
(iii) an operator:
Push it onto the stack.
Pop and display stack elements until a left
parenthesis is encountered, but do not display
it. (Error if stack empty with no left
parenthesis found.)
If stack empty or token has higher priority
than top stack element, push token onto stack.
(Left parenthesis in stack has lower priority
than operators)
(iv) an operand:
Otherwise, pop and display the top stack
element; then repeat the comparison of token
with new top stack item.
Display it.
3. When end of infix expression reached, pop and display stack items until
stack is empty.
42
Example:
(A+B*C)/(D-(E-F))
Push (
Display A
Push +
Display B
Push *
Display C
Read )
Pop *, Display *,
Pop +, Display +, Pop (
Push /
Push (
Display D
Push Push (
Display E
Push Display F
Read )
Pop -, Display -, Pop (
Read )
Pop -, Display -, Pop (
Pop /, Display /
Output
_____________
_____________
_____________
_____________
_____________
ABC*+D
ABC*+DE
ABC*+DEF
(
(
/
ABC*+DEFABC*+DEF-ABC*+DEF--/
/
(
/
43
Download