Data Structure-Stack
Data Structure-Stack
Hung-Ming Chen
NCTU EE
Fall 2023
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 1
Education, Inc. All rights reserved. 0-13-140909-3
Introduction to Stacks
• Consider a card game with a discard pile
– Discards always placed on the top of the pile
– Players may retrieve a card only from the top
What other examples
can you think of that
are modeled by a stack?
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 3
Education, Inc. All rights reserved. 0-13-140909-3
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
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 4
Education, Inc. All rights reserved. 0-13-140909-3
Example Program
• Consider a program to
do base conversion of
a number (ten to two)
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 5
Education, Inc. All rights reserved. 0-13-140909-3
Conversion from base ten to base two
/*--------------------------------------------------------------
This program uses a stack to convert the base-ten representation
of a positive integer entered as input to base two, which is
then output.
---------------------------------------------------------------------*/
#include <iostream>
using namespace std;
#include "Stack.h" // our own -- <stack> for STL version
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
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 << endl;
cout << "\nMore (Y or N)? ";
cin >> response;
}
while (response == 'Y' || response == 'y'); 6
}
Selecting Storage Structure
• Model with an array
– Let position 0 be top of stack
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 7
Education, Inc. All rights reserved. 0-13-140909-3
Selecting Storage Structure
• A better approach is to let position 0 be the
bottom of the stack
Note beginning
of Stack.h file,
• Thus our design will include Fig. 7.3
Class Invariant:
1. The stack elements (if any) are stored in positions
0, 1, . . ., myTop of myArray.
2. -1 <= myTop < STACK_CAPACITY
--------------------------------------------------------------*/
#include <iostream>
using namespace std;
#ifndef STACK
#define STACK
private:
/***** Data Members *****/
StackElement myArray[STACK_CAPACITY];
int myTop;
};
9
#endif
Implementing Operations
• Constructor
– 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
• Output routine added for testing
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 10
Education, Inc. All rights reserved. 0-13-140909-3
The Stack Class
• The completed Stack.h file, Fig. 7.4A
– All functions defined
– Note use of typedef mechanism
• Implementation file, Stack.cpp, Fig 7.4B
• Driver program to test the class, Fig 7.5
– Creates stack of 4 elements
– Demonstrates error checking for stack full, empty
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 11
Education, Inc. All rights reserved. 0-13-140909-3
Stack.h (Stack Class)
#include <iostream>
void display(ostream & out) const;
#ifndef STACK /*-----------------------------------------------------------
#define STACK Display values stored in the stack.
const int STACK_CAPACITY = 128; Precondition: ostream out is open.
typedef int StackElement;
Postcondition: Stack's contents, from top down, have
class Stack been output to out.
{ -----------------------------------------------------------*/
public:
/***** Function Members *****/ StackElement top() const;
/***** Constructor *****/ /*-----------------------------------------------------------
Stack(); Retrieve value at top of stack (if any).
/*----------------------------------------------------------
Construct a Stack object. Precondition: Stack is nonempty
Precondition: None.
Postcondition: Value at top of stack is returned, unless
Postcondition: An empty Stack object has been constructed the stack is empty; in that case, an error message is
(myTop is initialized to -1 and myArray is an array displayed and a "garbage value" is returned.
with STACK_CAPACITY elements of type StackElement). ----------------------------------------------------------*/
-----------------------------------------------------------*/
void pop();
bool empty() const; /*-----------------------------------------------------------
/*----------------------------------------------------------- Remove value at top of stack (if any).
Check if stack is empty.
Precondition: None
Postcondition: Returns true if stack is empty and
Precondition: Stack is nonempty.
false otherwise. Postcondition: Value at top of stack has been removed,
-----------------------------------------------------------*/ unless the stack is empty; in that case, an error
message is displayed and execution allowed to proceed.
void push(const StackElement & value); ----------------------------------------------------------*/
/*-----------------------------------------------------------
Add a value to a stack. private:
/***** Data Members *****/
Precondition: value is to be added to this stack StackElement myArray[STACK_CAPACITY];
Postcondition: value is added at top of stack provided
int myTop;
there is space; otherwise, a stack-full message is
displayed and execution is terminated. }; // end of class declaration
-----------------------------------------------------------*/
#endif
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 12
Education, Inc. All rights reserved. 0-13-140909-3
#include <iostream>
Implementation
using namespace std; //--- Definition of display()
void Stack::display(ostream & out) const
#include "Stack.h" {
for (int i = myTop; i >= 0; i--)
//--- Definition of Stack constructor
Stack::Stack() out << myArray[i] << endl;
: myTop(-1) }
{}
//--- Definition of top()
//--- Definition of empty()
StackElement Stack::top() const
bool Stack::empty() const
{ {
return (myTop == -1); if ( !empty() )
} return (myArray[myTop]);
else
//--- Definition of push()
{
void Stack::push(const StackElement & value)
{ cerr << "*** Stack is empty "
if (myTop < STACK_CAPACITY - 1) //Preserve stack " -- returning garbage value ***\n";
invariant return *(new StackElement);
{
}
++myTop;
myArray[myTop] = value; }
}
else //--- Definition of pop()
{ void Stack::pop()
cerr << "*** Stack full -- can't add new value ***\n"
{
"Must increase value of STACK_CAPACITY in
Stack.h\n"; if ( !empty() )
exit(1); myTop--;
} else
}
cerr << "*** Stack is empty -- "
"can't remove a value ***\n";
}
13
Test Driver
/*---------------------------------------------------------------------
Driver program to test the Stack class.
----------------------------------------------------------------------*/
#include <iostream>
#include <iomanip>
using namespace std;
#include "Stack.h"
int main()
{
Stack s;
cout << "Stack created. Empty? " << boolalpha << s.empty() << endl;
while (!s.empty())
{
cout << "Popping " << s.top() << endl;
s.pop();
}
cout << "Stack empty? " << s.empty() << endl;
cout << "Top value: " << s.top() << endl;
cout << "Trying to pop: " << endl;
s.pop();
}
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 14
Education, Inc. All rights reserved. 0-13-140909-3
Dynamic Array
to Store Stack Elements
• Same issues regarding static arrays for
stacks as for lists
– 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
• Note additional data members required
– DStack Data Members
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 15
Education, Inc. All rights reserved. 0-13-140909-3
Dynamic Array
to Store Stack Elements
• Constructor 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
• Note implementation of constructor for
DStack
• Fig 7.6A DStack.h, Fig. 7.6B DStack.cpp
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 16
Education, Inc. All rights reserved. 0-13-140909-3
#include <iostream>
Dstack.h
void push(const StackElement & value);
using namespace std; /*-----------------------------------------------------------
Add a value to a stack.
#ifndef DSTACK
#define DSTACK Precondition: value is to be added to this stack
Postcondition: value is added at top of stack provided
typedef int StackElement; there is space; otherwise, a stack-full message is
displayed and execution is terminated.
class Stack -----------------------------------------------------------*/
{
public: void display(ostream & out) const;
/***** Function Members *****/
/***** Constructors *****/ StackElement top() const;
Stack(int numElements = 128); /*-----------------------------------------------------------
/*---------------------------------------------------------- Retrieve value at top of stack (if any).
Construct a Stack object.
Precondition: Stack is nonempty
Precondition: None. Postcondition: Value at top of stack is returned, unless
Postcondition: An empty Stack object has been constructed the stack is empty; in that case, an error message is
(myTop is initialized to -1 and myArray is an array displayed and a "garbage value" is returned.
with numElements (default 128) elements of type ----------------------------------------------------------*/
StackElement).
-----------------------------------------------------------*/ void pop();
/*-----------------------------------------------------------
Stack(const Stack & original); Remove value at top of stack (if any).
/*----------------------------------------------------------
Copy Constructor Precondition: Stack is nonempty.
Postcondition: Value at top of stack has been removed,
Precondition: original is the stack to be copied and unless the stack is empty; in that case, an error
is received as a const reference parameter. message is displayed and execution allowed to proceed.
Postcondition: A copy of original has been constructed. ----------------------------------------------------------*/
-----------------------------------------------------------*/
private:
/***** Destructor *****/ /***** Data Members *****/
~Stack(); int myCapacity, // capacity of stack
myTop; // top of stack
/***** Assignment *****/ StackElement * myArray; // dynamic array to store elements
Stack & operator= (const Stack & original);
}; // end of class declaration
bool empty() const; 17
#endif
Implementation
#include <iostream>
//--- Definition of Stack copy constructor
#include <cassert>
Stack::Stack(const Stack & original)
#include <new>
: myCapacity(original.myCapacity), myTop(original.myTop)
using namespace std;
{
//--- Get new array for copy
#include "DStack.h"
myArray = new(nothrow) StackElement[myCapacity];
// allocate array in copy
//--- Definition of Stack constructor
Stack::Stack(int numElements)
if (myArray != 0) // check if memory available
{
// copy original's array member into this new array
assert (numElements > 0); // check precondition
for (int pos = 0; pos < myCapacity; pos++)
myCapacity = numElements; // set stack capacity
myArray[pos] = original.myArray[pos];
// allocate array of this capacity
else
myArray = new(nothrow) StackElement[myCapacity];
{
if (myArray != 0) // memory available
cerr << "*Inadequate memory to allocate stack ***\n";
myTop = -1;
exit(1);
else
}
{
}
cerr << "Inadequate memory to allocate stack \n"
" -- terminating execution\n";
//--- Definition of Stack destructor
exit(1);
Stack::~Stack()
} // or assert(myArray != 0);
{
}
delete [] myArray;
}
18
Implementation (cont’d) //--- Definition of push()
//--- Definition of assignment operator
void Stack::push(const StackElement & value)
Stack & Stack::operator=(const Stack & original)
{ {
if (this != &original) // check that not st = st if (myTop < myCapacity - 1) //Preserve stack invariant
{ {
//-- Allocate a new array if necessary ++myTop;
if (myCapacity != original.myCapacity) myArray[myTop] = value;
{ }
delete[] myArray; // destroy previous array else
{
myCapacity = original.myCapacity; // copy myCapacity cerr << "*** Stack full -- can't add new value ***\n"
myArray = new StackElement[myCapacity]; "Must increase value of STACK_CAPACITY in Stack.h\n";
if (myArray == 0) // check if memory available
exit(1);
{
}
cerr << "*** Inadequate memory ***\n";
exit(1); }
}
}
//--- Copy original's array into this myArray //--- Definition of top()
for (int pos = 0; pos < myCapacity; pos++) StackElement Stack::top() const
myArray[pos] = original.myArray[pos]; {
if ( !empty() )
myTop = original.myTop; // copy myTop member return (myArray[myTop]);
} else
return *this; {
}
cerr << "*** Stack is empty "
" -- returning garbage value ***\n";
//--- Definition of empty()
return *(new StackElement);
bool Stack::empty() const
{ }
return (myTop == -1); }
}
//--- Definition of pop()
//--- Definition of display() void Stack::pop()
void Stack::display(ostream & out) const {
{ if ( !empty() )
for (int i = myTop; i >= 0; i--) myTop--;
out << myArray[i] << endl; else
} cerr << "*** Stack is empty -- "
"can't remove a value ***\n";
19
}
Dynamic Array
to Store Stack Elements
• Class Destructor needed
– Avoids memory leak
– Deallocates array allocated by constructor
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 21
Education, Inc. All rights reserved. 0-13-140909-3
Dynamic Array
to Store Stack Elements
• Assignment operator
– Again, deep copy needed
– copies member-by-member, not just address
• Note implementation of algorithm in
operator= definition
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 22
Education, Inc. All rights reserved. 0-13-140909-3
Further Considerations (1/2)
• What if dynamic array initially allocated for
stack is too small?
– Terminate execution?
– Replace with larger array!
• Creating a larger array
– Allocate larger array
– Use loop to copy elements into new array
– Delete old array
– Point myArray variable at this new array
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 23
Education, Inc. All rights reserved. 0-13-140909-3
Further Considerations (2/2)
• Another weakness – the type must be set
with typedef mechanism
• This means we can only have one type of
stack in a program
– Would require completely different stack
declarations and implementations
• Solution coming in Chapter 9
– class templates
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 24
Education, Inc. All rights reserved. 0-13-140909-3
Linked Stacks
• Another alternative to allowing stacks to grow
as needed
• Linked list stack needs only one data
member
– Pointer myTop
– Nodes allocated (but not
part of stack class)
• Note declaration, Fig. 7-11
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 25
Education, Inc. All rights reserved. 0-13-140909-3
Linked Stack
class LStack
{
public:
/***** Function Members *****/
// Prototypes same as in preceding section
private:
/*** Node class ***/
class Node
{
public:
StackElement data;
Node * next;
//--- Node constructor
Node(StackElement value, Node * link = 0)
/*------------------------------------------------------
Precondition: value is received
Postcondition: A Node has been constructed with value
in its data part and itb next part set to link
(default 0).
------------------------------------------------------*/
{ data = value; next = link; }
};
28
Implementing Linked Stack
Operations
• Pop
– Delete first node in the
linked list
ptr = myTop; View
myTop = myTop->next; definitions in
delete ptr; Fig. 7.12
• Output
– Traverse the list
for (ptr = myTop;
ptr != 0; ptr = ptr->next)
out << ptr->data << endl;
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 29
Education, Inc. All rights reserved. 0-13-140909-3
Implementing Linked Stack
Operations
• Destructor
– Must traverse list and deallocate nodes
– Note need to keep track of ptr->next before
calling delete ptr; View
definitions in
• Copy Constructor Fig. 7.12
– Traverse linked list,
copying each element
into new node
– Attach new node
to copy
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 30
Education, Inc. All rights reserved. 0-13-140909-3
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
• View completed linked list version of stack
class, Fig 7.12
• Note driver program, Fig. 7.12C
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 31
Education, Inc. All rights reserved. 0-13-140909-3
Test Driver
/*---------------------------------------------------------------------
Driver program to test the Stack class.
----------------------------------------------------------------------*/
32
Application of Stacks (1/2):
Function Execution
Consider events when a function begins
execution
• Activation record (or stack frame) is created
• Stores the current environment for that
function.
• Contents:
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 33
Education, Inc. All rights reserved. 0-13-140909-3
Sample Program Segment
int main()
{
int a = 3;
f1(a);
cout << endl; // A: Return here after f1 finishes
}
void f1(int x)
{
cout << f2(x + 1); // B: Return here after f2 finishes
}
int f2(int p)
{
int q = f3(p/2); // C: Return here after f3 finishes
return 2 * q;
}
int f3(int n)
{
return n * n + 1;
}
34
Run-time 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
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 35
Education, Inc. All rights reserved. 0-13-140909-3
Use of Run-time Stack
When a function is called …
• Copy of activation record pushed onto run-
time stack
• Arguments copied into parameter spaces
• Control transferred to starting address of
body of function
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 36
Education, Inc. All rights reserved. 0-13-140909-3
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
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 39
Education, Inc. All rights reserved. 0-13-140909-3
Postfix and Prefix Examples
INFIX RPN (POSTFIX) PREFIX
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
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 40
Education, Inc. All rights reserved. 0-13-140909-3
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 4 + 5 6 - - *
→ 2 3 4 + 5 6 - - *
→ 2 7 5 6 - - *
→ 2 7 5 6 - - *
→ 2 7 -1 - *
→ 2 7 -1 - * → 2 8 * → 2 8 * → 16
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 41
Education, Inc. All rights reserved. 0-13-140909-3
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) Get the next token (const, var, operator) in the
expression
b) Operand – push onto stack Note: if only 1 value on
Operator – do the following stack, this is an invalid
i. Pop 2 values from stack RPN expression
ii. Apply operator to the two values
iii. Push resulting value back onto stack
3. When end of expression encountered, value of
expression is the (only) number left in stack
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 42
Education, Inc. All rights reserved. 0-13-140909-3
Evaluation
of Postfix
• Note the
changing
status of the
stack
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 43
Education, Inc. All rights reserved. 0-13-140909-3
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
x y
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 44
Education, Inc. All rights reserved. 0-13-140909-3
/
Traverse the tree in Left-Right-Parent
order (postorder) to get RPN:
* -
A B +C*DE-/
+ C D E
Traverse tree in Parent-Left-Right /
order (preorder) to get prefix: A B
* -
/ * + A BC- D E
+ C D E
/
Traverse tree in Left-Parent-Right
order (inorder) to get infix: A B
* -
— must insert ()'s
+ C D E
( ((A + B) * C)/(D - E) )
A B
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 45
Education, Inc. All rights reserved. 0-13-140909-3
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 + *
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 46
Education, Inc. All rights reserved. 0-13-140909-3
Stack Algorithm to Convert Infix to Postfix
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 47
Education, Inc. All rights reserved. 0-13-140909-3
Stack Algorithm 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
3. When end of infix reached, pop and display
stack items until empty
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 48
Education, Inc. All rights reserved. 0-13-140909-3
Converting Infix Expression to
Postfix
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 49
Education, Inc. All rights reserved. 0-13-140909-3
Converting Infix Expression to
Postfix
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson 50
Education, Inc. All rights reserved. 0-13-140909-3