CS-2001
Data Structures
Fall 2022
Introduction to Stack ADT
Mr. Muhammad Usman Joyia
National University of Computer
and Emerging Sciences,
Faisalabad, Pakistan.
1
Roadmap
Previous Lecture
• Variations of linked lists
– Doubly linked lists
– Circular Linked lists
Today
• Introduction to Stack
– Common applications
– Array Based-Implementation
– Linked-list Based Implementation
2
Stack
• A structure consisting of homogeneous elements and:
– Insertion and deletions takes place at one end called top
– It is a commonly used abstract data type with two major
operations, namely push and pop.
• Other names
– Last In First Out (LIFO) Structure
– First In Last Out (FILO) Structure
3
Real life scenarios…
• Books on floor
• Dishes on a shelf
• In programming, consider doing X = (A+B) * (C+D)
4
Stack ADT Operations
• Stack ADT emphasizes specific operations
– Uses an explicit linear ordering (Random access is
intentionally revoked)
– Insertions and removals are performed individually.
– Inserted objects are pushed onto the stack
– Top of the stack is the most recent object pushed onto the
stack
– Push and pop operations changes the current top value of the
stack
5
Stack ADT – Operations (1)
• Graphically, the stack operations are viewed as follows:
6
Stack ADT – Operations (2)
• CreateStack(S)
– Make Stack S be an empty stack
• Top(S)
– Return the element at the top of stack S
• Pop(S)
– Remove the top element of the stack
• Push(S,x)
– Insert the element x at the top of the stack
• Empty(S)
– Return true if S is an empty stack and return false otherwise
7
Push and Pop Operations of Stack
8
Applications (1)
• Many applications
– Parsing code
Matching parenthesis problem
– Tracking function calls (Call stack)
– Reversing a string
– Infix to postfix Conversion
– Backtracking in Depth-First-Search
• The stack is a very simple data structure
– Given any problem, if it is possible to use a stack, this
significantly simplifies the solution
9
Use of Stack in Function Calls (1)
• When a function begins execution an activation record is
created to store the current execution environment for that
function
• Activation records all the necessary information about a
function call, including
– arguments passed by the caller function
– Local variables
– Content of the registers
– Return address to the caller function
Address of instruction following the function call
11
Use of Stack in Function Calls (2)
• Each invocation of a function has its own activation record
• Recursive/Multiple calls to the functions require several
activation records to exist simultaneously
• A function returns only after all functions it calls have
returned Last In First Out (LIFO) behavior
• A program/OS keeps track of all the functions that have
been called using run-time stack or call stack
12
Runtime Stack Example (1)
void main(){
int a=3;
f1(a); // statement A
cout << endl;
}
void f1(int x){
cout << f2(x+1); // statement B
}
int f2(int p){
int q=f3(p/2); // statement C
return 2*q;
}
int f3(int n){
return n*n+1;
}
13
Runtime Stack
• When a function is called …
– Copy of activation record pushed onto run-time stack
– Arguments copied into parameter spaces
– Control is transferred to starting address of body of function
Function
Return Local
Parameter value
value variables Return
s address
OS denotes that when execution of main() is
completed, it returns to the operating system
14
Runtime Stack Example (2)
void main(){
int a=3;
f1(a); // statement A
cout << endl;
}
void f1(int x){
cout << f2(x+1); // statement B
}
int f2(int p){
int q=f3(p/2); // statement C
return 2*q;
}
int f3(int n){
return n*n+1;
}
15
Static and Dynamic Stacks
• Two possible implementations of stack data structure
– Static, i.e., fixed size implementation using arrays
– Dynamic implementation using linked lists
16
Array-based Implementation
17
Array Implementation – First Solution (1)
• Elements are stored in contiguous cells of an array
• New elements can be inserted to the top of the list
top last-pushed
Element
Second-last
Element List
1st pushed
Element
Empty
maxlengt
h
18
Array Implementation – First Solution (2)
1
3
2
2
1
1
• Problem
– Every PUSH and POP requires moving the entire array up and
down
– Fixed size 19
Array Implementation – Tweaked Solution (2)
1 1st pushed Element
2 2nd -pushed List
Element
…
top Last-pushed
Element
Empty
maxlengt
h
Idea
• Anchor the bottom of the stack at the start of the array
• Let the stack grow towards the last of the array
• Top indicates the current position of the recently inserted
stack element
20
Array Implementation – Code (1)
class IntStack
{
private:
int *stackArray;
int stackSize;
int top;
public:
IntStack(int);
~IntStack( );
bool push(int);
bool pop(int &);
bool isFull();
bool isEmpty();
};
21
Array Implementation – Code (2)
• Constructor
IntStack::IntStack(int size) //constructor
{
stackArray = new int[size];
stackSize = size;
top = -1;
}
• Destructor
IntStack::~IntStack(void) //destructor
{
delete [] stackArray;
}
22
Array Implementation – Code (3)
• isFull function
bool IntStack::isFull(void)
{
if (top == stackSize - 1)
return true;
else
return false;
// return (top == stackSize-1);
}
• isEmpty function
bool IntStack::isEmpty(void)
{
return (top == -1);
}
23
Array Implementation – Code (4)
• push function inserts the argument num onto the stack
bool IntStack::push(int num)
{
if (isFull())
{
cout << "The stack is full.\n";
return false;
}
top++;
stackArray[top] = num;
return true;
}
24
Array Implementation – Code (5)
• Pop function removes the value from top of the stack and
returns it as a reference
bool IntStack::pop(int &num)
{
if (isEmpty())
{
cout << "The stack is empty.\n";
return false;
}
num = stackArray[top];
top--;
return true;
}
25
Using Stack (1)
int main()
{
IntStack stack(4);
stackArra [0] top -1
y [1]
stackSize 4
[2
][3
]
}
26
Using Stack (2)
int main()
{
IntStack stack(4);
int catchVar;
cout << "Pushing Integers\n";
stack.push(5);
stack.push(10);
stack.push(15); stackArra 5 [0] top 3
stack.push(20); y [1]
1
stackSize 4
0
1 [2
5 ][3
2
0 ]
}
27
Using Stack (3)
int main()
{
IntStack stack(4); num 20
int catchVar;
cout << "Pushing Integers\n";
stack.push(5);
stack.push(10);
stack.push(15); stackArra 5 [0] top 2
stack.push(20); y [1]
1
stackSize 4
cout << "Popping...\n"; 0
1 [2
stack.pop(catchVar); 5 ][3
cout << catchVar << endl;
]
}
28
Using Stack (4)
int main()
Output:
{
IntStack stack(4); Pushing Integers
int catchVar; Popping…
20
cout << "Pushing Integers\n"; 15
stack.push(5); 10
stack.push(10);
stack.push(15);
5
stack.push(20);
cout << "Popping...\n";
stack.pop(catchVar);
cout << catchVar << endl;
stack.pop(catchVar);
cout << catchVar << endl;
stack.pop(catchVar);
cout << catchVar << endl;
stack.pop(catchVar);
cout << catchVar << endl;
return 0;
}
29
Any Question So Far?
37