0% found this document useful (0 votes)
19 views43 pages

04 Stacks

ffffffffffffffffffffffffffffffffffffffffffffffff

Uploaded by

sultanahimed
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views43 pages

04 Stacks

ffffffffffffffffffffffffffffffffffffffffffffffff

Uploaded by

sultanahimed
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 43

Read §4.1-4.

4. Stacks For Lab 5: Read §5.1-5.2

Introduction
Consider the 4 problems on pp.
170-1
(3) Parentheses checker
(1) Model the discard pile (4) Calculate and display
in a card game base-two
(2) Model a railroad representation
switching yard
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 LIFO (Last-In-First-Out)


structure.
2
Stack as an ADT
A stack is an ordered collection of data items in
which access is possible only at one end (called
the 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 is from spring-loaded
Adding
stack a plate
of plates in apushes those below
cafeteria:
it
Removing
down a stack
in the plate pops those below
it 3
up one position.
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.
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
***************************************************/

#include "Stack.h" // our own -- <stack> for STL version


#include <iostream>
using namespace std;

int main()
{
unsigned number, // the number to be converted
remainder; // remainder when number is
// divided by 2
Stack stackOfRemainders; // stack of remainders
char response; // user response

6
do
{
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;
}
cout << "\nMore (Y or N)? "; cin >> response;
}
while (response == 'Y' || response == 'y');
} 7
Building a Stack Class
Two steps:
1. Design the class; and
2. Implement the class.

1. Designing a Stack Class


Identify the operations needed to manipulate
"real-world" objects being modeled by class.
Operations are described:
Independent of class implementation.
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: 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.
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
Push 75
Push
89
64, Pop Pop
Push 64
0 0 75 0 89 0 64 0 89
1 1 1 75 1 89 1 75
2 2 2 2 75 2
3 3 3 3 3
4 4 4 4 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 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 Push
stack.
75 Push 89 Push 64 Pop Note: We
4 4 4 4 4 don't clear
3 3 3 3 3
2 2 2 this.
myTop 2 64 2 64
1 1 myTop 1 89 1 89 myTop 1 89
0 myTop 0 75 0 75 0 75 0 75
myTop
myTop = - myTop = 0 myTop = 1 myTop = 2 myTop = 1
1

11
Note: No moving of array
Stack's Data
Members
Provide:
• An array data member to hold the stack
elements.
• An integer data member to indicate the top of the
stack.
Problems: We 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 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
3. An
charalternative
or . . . to using and changing a typedef: A template
to build a Stack class is written whose element type is left
unspecified.
The element type is passed as a special kind of parameter 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
If we putqualification
 without 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:
Stack::StackElement
Stack::
5. If we were to STACK_CAPACITY
make STACK_CAPACITY a data member, we would
probably make it a static data member:
static const int STACK_CAPACITY = 128;
This makes it a property of the class usable by all class objects,
but they 14
do not have their own copies of STACK_CAPACITY.
//Stack.h
NOTE THE
DOCUMENTATION
/* 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:
StackElement myArray[STACK_CAPACITY];
int myTop;
}; // end of class declaration
. . .
#endif

16
Stack's Function Members
Constructor:

class Stack NOTE THE


DOCUMENTATION
{
public:
/*--- Constructor ---
Precondition: A stack has been declared.
Postcondition: Stack has been constructed
as an empty stack. Simple
*/ enough to
Stack(); inline?
...
} // end of class declaration Yes

inline Stack::Stack() { myTop = -1; }

17
A declaration

Stack s;

will construct s as follows:

s 0 1 2 3 4 . . . 127
myArray ? ? ? ? ? . . . ?
myTop -1

18
empty:
Receives Stack containing it as a function member (perhaps
implicitly)
Returns: True ifYe
stack is empty, false otherwise.
Member
Const function?
function? (Shouldn't
s alter data Ye
Simple enough to
members)? Ye s
inline?
class Stack
s
{
public:
. . .
/* --- Is the Stack empty? ---
* Returns: true if the Stack containing this
* function is empty and false otherwise
***************************************************/
bool empty() const;
. . .
};// end of class declaration
inline bool Stack::empty() const
19
{ return (myTop == -1); }
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? true
or if boolalpha omitted or not
implemented: 20
push:
Receives Stack containing it as a function member (perhaps
implicitly)
Value to be added to stack
Returns: ModifiedYe stack (perhaps implicitly)
Const
Memberfunction?
Nos
function? Simple enough to inline?
Probably not

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
*************************************************/

void push(const StackElement & value);


21
Add to Stack.cpp:

void Stack::push(const StackElement & value)


{
if (myTop < STACK_CAPACITY - 1)
{ //Preserve stack invariant
++myTop;
myArray[myTop] = value;
} // or simply, myArray[++myTop] = 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: Stack containing it as a function member
(perhaps implicitly)
an ostream
Output: Contents Ye ofConst
Stack, from the
Ye top down.
Simple enough to Ye
Member function? s function? s inline? s
Add to class declaration:
/* --- Display values stored in the stack ---
*
* Receive: The ostream out
* Output: Stack's contents, from top down, to out
***************************************************/
void display(ostream & out) const;

Add to Stack.h
inline void Stack::display(ostream & out) const
{
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"; For your Queue class,
make sure output
s.push(129); works after array has
*/ "wrapped around."
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: Stack containing it as a function member
(perhaps implicitly)
Returns: Value at the top of the stack
Output: Error message
Ye if stack is empty
Member
Const function?
Yes
function?
Simple enoughs to No?
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
***************************************************/
StackElement top() const;

26
Add to Stack.cpp:
StackElement Stack::top() const
{
if (myTop >= 0) // or if (!empty())
return (myArray[myTop]);
else
{
cerr << "*** Stack is empty "
" -- returning garbage ***\n";
return myArray[STACK_CAPACITY-1];
}
} Output:
Add to driver at bottom: Stack contents:
8
cout << "Top value: " << s.top()
6
4
<< endl;
2
s empty? false
Top value: 8 27
pop:
Receives Stack containing it as a function member (perhaps
implicitly)
Returns: Stack with top element removed (perhaps implicitly)
Output: Error message
Ye Const if stack isNo
empty.
Simple enough to Ye
Member function?
s function? inline? s
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.
**************************************************/
void pop();
. . .
}; // end of class declaration

28
inline void Stack::pop()
{
if (myTop >= 0) // Preserve stack invariant
myTop--;
else
cerr << "*** Stack is empty -- "
"can't remove a value ***\n";
} Output:
Stack contents:
Add to driver at bottom: 8
while (!s.empty()) 6
{ 4
cout << "Popping " << s.top() 2
<< endl; s empty? false
s.pop(); Top value: 8
} Popping 8
cout << "s empty? " << s.empty() Popping 6
<< endl; Popping 4
Popping 2
s empty? true 29
Read §4.3
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
parameters
include:
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
30
execution?
Problem:FunctionA can call FunctionB Example
on slide 33
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.
So, the order of returns from a function is the reverse of
When FunctionB
function finishes,
invocations; that control
is, LIFOshould return to
behavior.
FunctionA.
 Use a stack to store the activation records. Since it
is manipulated at run-time, it is called the run-time
stack.
31
What happens when a function is 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.

What happens when a function terminates?


1. Pop activation record of terminated function from
the
run-time stack
2. Use new top activation record to restore the 32
Examples
Trace run-time stack for int factorial(int n)
the following: {
. . . if (n < 2)
int main() return 1;
{ . . . else
f2(...); return n * factorial(n-1);
f3(...); }
} What happens to the run-time stack
void f1(...) {. . .} when the following statement
void f2(...) executes?
{... f1(...); ...} int answer = factorial(4);
void f3(...)
{... f2(...); ...}

This pushing and popping of the run-time stack is


the real overhead associated with function calls
that inlining avoids 33
by replacing the function call with the body of the
Application of Stacks: RPN
1. What is RPN (Reverse Polish Notation)?
A notation for arithmetic expressions in which operators are
written
after the operands. Expressions can be written without
using
parentheses.
Developed by Polish logician, Jan Lukasiewics, in 1950's
Infix notation: operators written between the
operands
Examples:
Postfix " (RPN): operators written after the operands
INFIX
Prefix " : RPN (POSTFIX)
operators written PREFIX
before the operands
A + B A B + + A B
A * B + C A B * C + + * A B C
A * (B + C) A B C + * * A + B C
A - (B - (C - D)) A B C D - - - - A - B - C D
A - B - C - D A B - C - D - - - - A B C D 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 3 42+3546+-5-6*
- 
- *2 7 5 6 - - *
 2 7 5 6 - - *
 2 7 -1 - *
 2 7 -1 - *  2 8 *  2 8 *  16 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
Generate code:
the RPN expression.
b. If token is an operand, push it onto the stack. LOAD operand1
If it is an operator, then: op operand2
(i) Pop top two values from the stack. If stack STORE TEMP#:
does not contain two items, signal error due to a
Push TEMP#
malformed RPN and terminate evaluation.
(ii) Apply the operator to these two values.
(iii) Push the resulting value back onto the stack.
36
3. When the end of expression encountered, its value is on
A B C + D E - - *
Sample RPN Evaluation (p.
196)
Example: 2 3 4 + 5 6 - - *
Push 2 4
Push 3 3
Push 4 2
Read +
6
Pop 4, Pop 3, 3 + 4 = 7
Push 7 5
Push 5 7
Push 6 2
Read -
Pop 6, Pop 5,5 - 6 = -1
-1
Push -1
Read - 7
Pop -1, Pop 7,7 - -1 = 8 2
Push 8 8
Read *
2
Pop 8, Pop 2, 2 * 8 = 16
Push 16 16 37
Unary minus causes
problems

Example: 5 3 - -
OR 5 3 - -
5 3 - -  2 -
 5 -3 -  -2
 8
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)

+ * /

A * -
* C +

A B + C D E
B C

A B

x  y
39
x y
/
Traverse the tree in Left-Right-
Parent
* -
order (postorder) to get RPN:
A B+ C*D E-/
+ C D E
Traverse tree in Parent-Left- /
Right A B
order (preorder) to get prefix: -
*
/ * + A BC- D E
+ C D E

Traverse tree in Left-Parent- /


Right A B
order (inorder) to get infix * -
— must insert ()'s
( ((A + B) * C)/(D - E) ) + C D E

40
A B
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 + *

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: 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 onto
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. 42
(iv) an operand: Display it.
Example: (A+B*C)/(D-(E-F))
Push ( Output
Display A A *
Push + +
Display B AB
Push * (
Display C ABC +
Read )
(
Pop *, Display *, ABC*
Pop +, Display +, Pop ( ABC*+ (
Push /
Push ( -
Display D ABC*+D (
Push -
Push ( -
Display E ABC*+DE (
Push -
Display F ABC*+DEF /
-
Read )
Pop -, Display -, Pop ( ABC*+DEF- (
Read ) /
Pop -, Display -, Pop ( ABC*+DEF-- / 43
Pop /, Display / ABC*+DEF--/

You might also like