stack as an ADT

advertisement
stack as an ADT
A stack is an ordered collection of data items
access is possible only at one end ( top of the stack).
Basic operations
1. Construct a stack (usually empty)
2. Check if stack is empty
3. Push: Add an element at the top of the stack
4. Top: Retrieve the top element of the stack
5. Pop: Remove the top element of the stack
Terminology 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.
Example use of (LIFO) Stack
BASE-CONVERSION ALGORITHM
(See p. 171-2)
/* Display 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 from number divided by 2.
b. Push remainder onto the stack of remainders.
c. Replace number by the integer quotient of number divided by 2.
3. While the stack of remainders is not empty:
a. Retrieve and remove the remainder from the top of the stack
b. Display remainder.
Example -- Continued
// code that uses stack object stackOfRemainders
cout << "Enter positive integer to convert: ";
cin >> number;
while (number != 0)
{
remainder = number % 2;
stackOfRemainders.push(remainder);
number /= 2;
}
cout << "Base-two representation: ";
while (!stackOfRemainders.empty() )
{
remainder = stackOfRemainders.top();
stackOfRemainders.pop();
cout << remainder;
}
Designing a Stack Class
identify operations needed to manipulate "real-world" object modeled by class.
operations described
 independent of class implementation.
 in a manner independent of any specific representation of object.
Stack operations:
• Construction: Initializes an empty stack.
• Empty operation: Determines if stack contains any values
• Push operation: Modifies a stack by adding a value to top of stack
• Top operation: Retrieves the value at the top of the stack
• Pop operation: 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.
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
0
1
2
3
4
Push 75
0 75
1
2
3
4
Push 89
0 89
1 75
2
3
4
Push 64
0 64
1 89
2 75
3
4
Pop
0 89
1 75
2
3
4
+ features: This models the operation of the stack of plates.
– features: Not efficient to shift the array elements up and down in the array.
Implementing Stack Class -Refined
Instead of modeling the stack of plates, model a stack of books.
 Keep the bottom of stack at position 0
 Maintain a "pointer" myTop to the top of the stack.
e.g., Push 75, Push 89, Push 64, Pop
4
3
2
1
0
myTop
myTop = –1
4
3
2
1
myTop0
Push 75
75
4
3
2
myTop1
0
myTop = 0
Note: No moving of array elements.
Push 89
89
75
4
3
myTop2
1
0
myTop = 1
Push 64
64
89
75
4
3
2
myTop1
0
myTop = 2
Pop
64
89
75
myTop = 1
Implementing Stack Class -Continued
Begin the declaration of class by selecting data members:
Provide
 array data member to hold the stack elements.
 constant data member to refer to the capacity of the array
 integer data member to indicate the top of the stack.
Problems: need an array declaration of the form
ArrayElementType myArray[ARRAYCAPACITY];
What type should be used?
Solution (for now): Use the typedef mechanism:
typedef int StackElement;
// put this before the class declaration
What about the capacity?
const int STACK_CAPACITY = 128;
// put this before the class declaration
1.
Implementing Stack Class -Continued
typedef makes StackElement a synonym for int
2. The typedef outside the class makes it accessible
 throughout the class and
 in any file that #includes Stack.h
 without qualification
(Stack::StackElement needed if data member)
3. Want a stack of reals, or characters, or ... ?
Change the typedef
typedef double StackElementType;
or
typedef char StackElementType;
or . . .
When class library recompiled, array elements will be double or char or .
4. An alternative to using and changing a typedef: a template
A Stack class is built whose element type is left unspecified.
The element type is passed as a special kind of parameter at compile time.
Implementing Stack Class -Continued
#ifndef STACK
#define STACK
const int STACK_CAPACITY = 128;
typedef int StackElement;
class Stack
{
/***** Function Members *****/
public:
. . .
/***** Data Members *****/
private:
StackElement myArray[STACK_CAPACITY];
int myTop;
}; // end of class declaration
. . .
#endif
Implementing Stack Class Methods
/* --- Constructor Simple enough to inline? Yes
Precondition: A stack has been declared.
Postcondition: Stack has been constructed as an
empty stack.
*/
inline Stack::Stack() {myTop = -1;}
Stack S; // will construct S as follows:
S
0 1 2 3 4
myArray 127
? ? ? ? ?
myTop -1
. . .
. . .
?
Implementing Stack Class Methods
/* --- Is the Stack empty?
const function? (Shouldn't alter data members) Yes
Simple enough to inline? Yes --* Receive:stack containing function (implicitly)
* Returns: true if this Stack empty
*/
inline bool Stack::empty() const
{ return (myTop == -1); }
Implementing Stack Class Methods
/* --- Add a value to the stack
Simple enough to inline? Probably not --* Receive:
The Stack containing function (implicitly)
*
A value to be added to a Stack
* Pass back: Stack (implicitly)with value added
* Output:
"Stack full" message if no space for value
*/
// In Stack.cpp
void Stack::push(const StackElement & value)
{
if (myTop < STACK_CAPACITY - 1) // stack invariant
{
++myTop;
myArray[myTop] = value;
}
else
cerr << "*** Stack full:can't add new value ***\n"
<< "increase STACK_CAPACITY in Stack.h\n";
}
Implementing Stack Class Methods
/* --- Display values stored in the stack --*
const function? (Shouldn't alter data members?) Yes
Simple enough to inline? No
* Receive: Stack containing function (implicitly)
*
ostream out
* Output: The Stack's contents, from top down
*/
// in Stack.cpp
void Stack::display(ostream & out) const
{
for (int i = myTop; i >= 0; i--)
out << myArray[i] << endl;
}
Implementing Stack Class Methods
/* --- Return value at top of the stack --*
const function? Yes
Simple enough to inline? Probably not
* Receive: Stack containing function (implicitly)
* Return: value at the top of nonempty Stack
* Output: "Stack empty" message if stack empty
*/
// in Stack.cpp
StackElement Stack::top() const
{
if (myTop >= 0)
return (myArray[myTop]);
cerr << "*** Stack is empty ***\n";
}
Implementing Stack Class Methods
/* --- Remove value at top of the stack --*
const function? No
Simple enough to inline? Probably not
* Receive: Stack containing function (implicitly)
* Pass back: Stack containing function (implicitly)
*
with top value (if any) removed
* Output: "Stack-empty" message if stack is empty.
*/
// in Stack.cpp
void Stack::pop()
{
if (myTop >= 0)
// stack invariant
myTop--;
else
cerr << "** Stack empty:can't remove value *\n";
}
Run-time Stack
When a function begins execution (i.e., is activated),
an activation record (or stack frame) is created
to store the current environment for that function.
Contents of activation record include:
parameters
caller's state information (saved)
(e.g., contents of registers, return address)
local variables
temporary storage
Problem: FunctionA can call FunctionB; FunctionB can call FunctionC
When FunctionC finishes, control should return to FunctionB
When FunctionB finishes, control should return to FunctionA.
The order of returns from function is the reverse of function invocations: LIFO
 Use a stack to store the activation records
Run-time Stack
When a function called,
(1) Push a copy of its activation record onto the run-time stack
(2) Copy its arguments into the parameter spaces
(3) Transfer control to the address of the function's body
The top activation record in the run-time stack
is always that of the function currently executing.
When a function terminates,
(1) Pop activation record of terminated function
from the run-time stack
(2) Use new top activiation record to
restore the environment of the interrupted function
and resume execution of the interrupted function
overhead associated with function calls
 pushing and popping of the run-time stack
 avoided by inline functions (call replaced with body of function)
Reverse Polish Notation
RPN?
A notation for arithmetic expressions:
operators are written after the operands.
Expressions can be written without using parentheses
Developed by Polish logician, Jan Lukasiewics, in 1950's
Infix notation:
Postfix notation (RPN):
Prefix notation :
operators written between the operands
operators written after the operands
operators written before the operands
Examples:
INFIX
A + B
A * B + C
A * (B + C)
A–(B –(C – D))
A – B – C – D
A
A
A
A
A
RPN (POSTFIX)
B +
B * C +
B C + *
B C D - - B - C - D -
+
+
*
-
A
*
A
A
-
PREFIX
B
A B C
+ B C
- B - C D
- A B C D
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
2
3
3
7
7
7
7
8
4 + 5 6 - - *
4 + 5 6 - - *
5 6 - - *
5 6 - - *
-1 - *
-1 - *
*
 2 8 * 16
Evaluating RPN Expressions
STACK ALGORITHM
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, error due to a malformed RPN
Evaluation terminated
(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).
Evaluating RPN Expressions
Unary minus causes problems
Example: 5 3 -  5 3 -  5 -3 -  8
5 3 -  5 3 -  2 -  -2
Use a different symbol:
5 3 ~ 5 3 - ~
Sample RPN Evaluation
Example:
2 3 4 + 5 6 - - *
Push 2
Push 3
Push 4
Read +
Pop 4, Pop 3, 3 + 4 =
Push 7
Push 5
Push 6
Read Pop 6, Pop 5, 5 - 6 =
Push -1
Read Pop -1, Pop 7, 7 - -1
Push 8
Read *
Pop 8, Pop 2, 2 * 8 =
7
-1
= 8
16
Converting Infix to RPN I
By hand: Represent infix expression as an expression tree:
A * B + C
A * (B + C)
*
+
C
*
A
A
+
B
B
((A + B) * C) / (D - E)
/
-
*
+
A
C
B
D
E
C
Converting Infix to RPN I
Traverse the tree in Left-Right-Parent order to get RPN
Postorder
AB+C*DE-/
Traverse tree in Parent-Left-Right order to get Prefix
Preorder
/*+ABC-DE
Traverse tree in Left-Parent-Right order to get Infix -- must insert ()'s
inorder
((A+B)*C)/(D-E)
Converting Infix to RPN II
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.
Example:
((A + B) * C) / (D - E)
 (((A + B ) * C ) / (D - E) )
 (((A B + C * (D E - /

A B + C * D E - /
Converting Infix to RPN III
Stack Algorithm
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:
Push it onto the stack.
(ii) a right parenthesis:
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.)
(iii) an operator:
If stack empty or Token has higher priority than top stack element, push Token on stack.
( Left parenthesis in stack has lower priority than operators)
Otherwise, pop and display the top stack element; then
repeat the comparison of Token with new top stack item.
(iv)
an operand:
Display it.
3. When end of infix expression reached,
pop and display stack items until stack is empty.
Converting Infix to RPN III
Example:
((A+B)*C)/(D-E)
Push (
Push (
Display A
A
Push +
Display B
AB
Read )
Pop +, Display +, Pop (
AB+
Push *
Display C
AB+C
Read )
Pop *, Display *, Pop (
AB+C*
Push /
Push (
Display D
AB+C*D
Push Display E
AB+C*DE
Read )
Pop -, Display -, Pop (
AB+C*DEPop /, Display /
AB+C*DE-/
// stack now empty
Download