Module 4 Stack Data Structure
Module 4 Stack Data Structure
2. Introduction
This chapter focuses on stack data structure. Stack is one of the most covered
data structure in curriculum and are often used when there are interrupts to handle, or
when having recursive functions, or even when constructing a rudimentary AI for
games. It is also a very common data structure used in programs which has lot of
potential. This part also discusses basic features, operations/applications and
implementations of stacks.
3. Learning Outcome
At the end of this chapter the students are expected to:
• Describe the stack operations.
• Perform stack operations in a program.
• Evaluate arithmetic expressions in stacks.
4. Learning Content
Stack is an abstract data type with a bounded(predefined) capacity. It is a simple
data structure that allows adding and removing elements in a particular order. Every
time an element is added, it goes on the top of the stack and the only element that can
be removed is the element that is at the top of the stack, just like a pile of objects. It is
a first-in-last-out data structure with access only to the top of the data. Since many
languages does not provide facility for stack, it is backed by either arrays or linked list.
The values can be added and deleted on any side from an array. But in stack, insertion
and deletion is possible on only one side of the stack. Stacks hold objects, usually all
of the same type. It follows the concept of LIFO – last in first out where values can be
inserted (pushed) onto a stack or removed (popped) from the stack, and the value that
was pushed on the stack most recently is the first to be popped from it. Stack is a linear
list of items in which all additions and deletion are restricted to one end. Some
languages, like LISP and Python, do not call for stack implementations, since push and
pop functions are available for any list. All Forth-like languages (such as Adobe
PhotoScript) are also designed around language-defined stacks that are directly visible
to and manipulated by the programmer. Stacks holds objects. Common stack
operations are pop, push, peek (get the top element without removing it), is Empty
(checks whether stack is empty or not), and is Full (checks whether stack is full
or not).
end procedure
Implementation of isfull() function in C programming language:
Example
Isabela State University, Jones Campus
IT 211 Data Structure and Algorithms
bool isfull() {
if(top== MAXSIZE)
return true; else
return false;
}
isempty()
Algorithm of isempty() function − begin
procedure isempty
end procedure
Implementation of isempty() function in C programming language is slightly different. We
initialize top at -1, as the index in array starts from 0. So we check if the top is below zero
or -1 to determine if the stack is empty. Here's the code:
Example
bool isempty() {
if(top == -1)
return true; else
return false;
}
If the linked list is used to implement the stack, then in step 3, we need to allocate
space dynamically.
if stack is full
return null endif
top ← top + 1
stack[top] ← data
end procedure
Implementation of this algorithm in C, is very easy. See the following code:
Example
void push(int data) {
if(!isFull()) { top
= top + 1;
stack[top] = data;
} else {
printf("Could not insert data, Stack is full.\n");
}
Isabela State University, Jones Campus
IT 211 Data Structure and Algorithms
}
4.1.2. Pop Operation
Accessing the content while removing it from the stack, is known as a Pop Operation. In
an array implementation of pop() operation, the data element is not actually removed,
instead top is decremented to a lower position in the stack to point to the next value. But
in linked-list implementation, pop() actually removes data element and deallocates
memory space.
A Pop operation may involve the following steps −
• Step 1 − Checks if the stack is empty.
• Step 2 − If the stack is empty, produces an error and exit.
• Step 3 − If the stack is not empty, accesses the data element at which topis pointing.
• Step 4 − Decreases the value of top by 1.
• Step 5 − Returns success.
if stack is empty
return null endif
data ← stack[top]
top ← top - 1 return
data
end procedure
Implementation of this algorithm in C, is as follows:
Example
int pop(int data) {
if(!isempty()) {
data = stack[top];
top = top - 1;
return data; } else {
Below is a simple C++ program that implements stack data structure and also follows
the object-oriented programming (abstract data type) concepts.
# include<iostream>
using namespace std;
class Stack
{ int top;
public:
int a[10];
Stack()
{
top = -1;
}
void Stack::push(int x)
{
if(top >= 10)
{
cout << "Stack Overflow \n";
}
else
{
a[++top] = x;
cout << "Element Inserted \n";
}
}
int Stack::pop()
{
if(top < 0)
{
cout << "Stack Underflow \n";
return 0;
}
else
{
int d = a[top--];
return d;
}
}
void Stack::isEmpty()
{
if(top < 0)
{
cout << "Stack is empty \n";
}
else
{
cout << "Stack is not empty \n";
}
}
int main()
{
Stack s1;
s1.push(10);
s1.push(100);
}
4.2.1a Using Stack from the Standard Template Library (STL) in C++
Now that we have clearly defined the stack as an abstract data type we will turn
our attention to using a stack with the help of the Standard Template Library (STL) in
C++.
Unlike the given code above (which implemented stack in a user defined abstract
data structure), the STL has a well written implementation of the Stack class.
Isabela State University, Jones Campus
IT 211 Data Structure and Algorithms
The following stack implementation assumes that the end of the array will hold the
top element of the stack. As the stack grows (as be added on the end of the array.
pop operations will manipulate that same
//Tests the push, empty, size, pop,
and top methods of the stack end.
library. push operations occur), new items
will
#include <iostream>
#include <stack> // Calling Stack from the STL
int main() {
stack<int> newStack;
cout << "Top Element of the Stack: " << newStack.top() << endl;
return 0;
}
Self Check
Q-1: Given the following sequence of stack operations, what is the top item on the stack
when the sequence is complete?
stack<int> m;
m.push(5);
m.push(12);
m.pop();
m.push(27);
cout << m.top();
A. 5
B. 12
C. 27
D. The stack is empty
Answer: _____
Q-2: Given the following sequence of stack operations, what is the top item on the stack
when the sequence is complete?
stack<int> m;
m.push(37);
m.push(56);
m.push(4); while
(!m.empty()){
m.pop();
m.pop();
}
A. 37
B. the stack is empty
C. an error will occur
D. 4
Answer: _____
4.3 Evaluation of Arithmetic Operations
Isabela State University, Jones Campus
IT 211 Data Structure and Algorithms
requires that its operators come after the corresponding operands. A few more examples
should help to make this a bit clearer (see tables below).
In prefix, A + B * C would be written as + A * B C . The multiplication operator
comes immediately before the operands B and C, denoting that * has precedence over +.
The addition operator then appears before the A and the result of the multiplication.
In postfix, the expression A + B * C would be A B C * +. Again, the order of
operations is preserved since the * appears immediately after the B and the C, denoting
that * has precedence, with + coming after. Although the operators moved and now
appear either before or after their respective operands, the order of the operands stayed
exactly the same relative to one another.
4.3.1 Examples of Infix, Prefix, and Postfix
Common Expression
(A + B) * (C + D) *+AB+CD AB+CD+*
So far, we have used ad hoc methods to convert between infix expressions and
the equivalent prefix and postfix expression notations. As you might expect, there are
algorithmic ways to perform the conversion that allow any expression of any complexity
to be correctly transformed.
The first technique that we will consider uses the notion of a fully parenthesized
expression that was discussed earlier. Recall that A + B * C can be written as (A + (B *
C)) to show explicitly that the multiplication has precedence over the addition. On closer
observation, however, you can see that each parenthesis pair also denotes the beginning
and the end of an operand pair with the corresponding operator in the middle.
Look at the right parenthesis in the subexpression (B * C) above. If we were to
move the multiplication symbol to that position and remove the matching left parenthesis,
giving us B C *, we would in effect have converted the subexpression to postfix notation.
If the addition operator were also moved to its corresponding right parenthesis position
and the matching left parenthesis were removed, the complete postfix expression would
result (see figure below).
If we do the same thing but instead of moving the symbol to the position of the right
parenthesis, we move it to the left, we get prefix notation (see figure below). The position
of the parenthesis pair is actually a clue to the final position of the enclosed operator.
In this algorithm, all operands are printed (or sent to output) when they are read.
There are more complicated rules to handle operators and parentheses.
Example:
A + B * C becomes A B C * +
The order in which the operators appear is not reversed. When the '+' is read, it has lower
precedence than the '*', so the '*' must be printed first.
Algorithm
1. Create an empty stack called opstack for keeping operators. Create an empty vector
for output.
2. Scan the current token of the input vector from left to right (using a loop).
o If the token is an operand, append it to the end of the output list(vector).
o If the token is a left parenthesis, push it on the opstack.
o If the token is a right parenthesis, pop the opstack until the corresponding left
parenthesis is removed. Append each operator to the end of the output vector.
o If the token is an operator, *, /, +, or -, push it on the opstack. However, first
remove any operators already on the opstack that have higher or equal
precedence and append them to the output vector.
3. When the input expression has been completely processed, check the opstack. Any
operators still on the stack can be removed and appended to the end of the output
vector.
The following figure shows the conversion algorithm working on the expression A
* B + C * D. Note that the first * operator is removed upon seeing the + operator. Also, +
stays on the stack when the second * occurs, since multiplication has precedence over
addition. At the end of the infix expression the stack is popped twice, removing both
operators and placing + as the last operator in the postfix expression.
Isabela State University, Jones Campus
IT 211 Data Structure and Algorithms
#include <iostream>
#include <stack>
#include <unordered_map>
#include <string>
#include <vector>
string s(postfixVector.begin(),postfixVector.end());
return s;
}
int main() { cout <<"infix: A * B + C * D\n" << "postfix: "; cout <<
infixToPostfix("A * B + C * D") << endl; cout << "infix: ( A + B ) * C -
( D - E ) * ( F + G )\n" << "postfix: "; cout << infixToPostfix("( A + B )
* C - ( D - E ) * ( F + G )") << endl;
return 0;
}
Postfix Evaluation
Isabela State University, Jones Campus
IT 211 Data Structure and Algorithms
The next figure below shows a slightly more complex example, 7 8 + 3 2 + /. There
are two things to note in this example. First, the stack size grows, shrinks, and then grows
again as the subexpressions are evaluated. Second, the division operation needs to be
handled carefully. Recall that the operands in the postfix expression are in their original
order since postfix changes only the placement of operators. When the operands for the
division are popped from the stack, they are reversed. Since division is not a commutative
operator, in other words 15/5 is not the same as 5/15, we must be sure that the order of
the operands is not switched.
The complete function for the evaluation of postfix expressions is shown in the following
C++ Implementation code. To assist with the arithmetic, a helper function doMath is
defined that will take two operands and an operator and then perform the proper
arithmetic operation.
C++ Implementation
//Solves a postfix math problem.
#include <iostream>
#include <stack>
#include <string>
}
return operandStack.top();
}
int main() {
cout << "7 8 + 3 2 + /" << endl;
cout << postfixEval("7 8 + 3 2 + /") << endl;
return 0;
}
Self Check
Q-1: Without using the activecode infixToPostfix function, convert the following
expression to postfix 10 + 3 * 5 / (16 - 4).
Answer: ____________________________
Q-2: What is the result of evaluating the following: 17 10 + 3 * 9 / ? Answer:
==
____________________________
For example:
Input: { 10, 4, 6, 3, 5 }
Output: 10, 6, 5 (The elements greater than all elements to its right)
6. Recommended learning materials and resources for supplementary reading.
References:
E. B. Costa, A. M. Toda, M. A. A. Mesquita and J. D. Brancher, "DSLEP (Data Structure
Learning Platform to Aid in Higher Education IT Courses)," Journal of Social, Behavioral,
Educational, Economic, Business and Industrial Engineering, vol. 8, no. 4, pp. 1143-1148,
2014.
YoYo Games Ltd., "DS Stacks," YoYo Games Ltd., 2018.
https://docs.yoyogames.com
/index.html?page=source%2Fdadiospice%2F002_reference%2Fdata%20structures%2F
in dex.html. [Accessed 30 April 2019].
https://runestone.academy/runestone/books/published/cppds/LinearBasic/Implementing
aStackCpp.html
https://runestone.academy/runestone/books/published/cppds/LinearBasic/InfixPrefixand
PostfixExpressions.html https://www.techiedelight.com/Category/stack/
Books:
B. Costa, A. M. Toda, M. A. A. Mesquita and J. D. Brancher, "DSLEP (Data
Structure Learning Platform to Aid in Higher Education IT Courses)," Journal of
Social, Behavioral, Educational, Economic, Business and Industrial Engineering,
vol. 8, no. 4, pp. 1143-1148, 2014.
Prepared by:
Rowell F. Santiago
Assistant Professor 1
ISU Jones Campus