Module 2 Stacks
Module 2 Stacks
Module-2 The Stack – Definition and examples, primitive operations, Example. Representing Stacks in C, Example: Infix, Postfix and Prefix,
converting an Expression from Infix to Prefix and Program. Text Book -1- Chapter – 2.1-2.3
Recursion – Recursive Definition and Processes, Recursion in C, Writing Recursive Programs. Recursions - Text Book -1-Chapter – 3.1-3.3
● Pushing an element onto the stack is like adding a new plate on top.
This strategy states that the element that is inserted last will come out first. You can take a pile of plates kept on top of each other as a real-life
example. The plate which we put last is on the top and since we remove the plate that is at the top, we can say that the plate that was put last comes
out first.
Stack follows LIFO (Last In First Out) Principle so the element which is pushed last is popped first.
● Fixed Size Stack : As the name suggests, a fixed size stack has a fixed size and cannot grow or shrink dynamically. If the stack is full and an attempt is
made to add an element to it, an overflow error occurs. If the stack is empty and an attempt is made to remove an element from it, an underflow error occurs.
● Dynamic Size Stack : A dynamic size stack can grow or shrink dynamically. When the stack is full, it automatically increases its size to accommodate the
new element, and when the stack is empty, it decreases its size. This type of stack is implemented using a linked list, as it allows for easy resizing of the stack.
In order to make manipulations in a stack, there are certain operations provided to us.
Adds an item to the stack. If the stack is full, then it is said to be an Overflow condition.
● Before pushing the element to the stack, we check if the stack is full .
● If the stack is full (top == capacity-1) , then Stack Overflows and we cannot insert the element to the stack.
● Otherwise, we increment the value of top by 1 (top = top + 1) and the new value is inserted at top position .
● The elements can be pushed into the stack till we reach the capacity of the stack.
Removes an item from the stack. The items are popped in the reversed order in which they are pushed. If the stack is empty, then it is said to be an Underflow
condition.
● Before popping the element from the stack, we check if the stack is empty .
● If the stack is empty (top == -1), then Stack Underflows and we cannot remove any element from the stack.
● Otherwise, we store the value at top, decrement the value of top by 1 (top = top – 1) and return the stored top value.
● Before returning the top element from the stack, we check if the stack is empty.
Representing Stacks in C
The basic operations that can be performed on a stack include push, pop, and peek. There are two ways to implement a stack –
● Using Array
In an array-based implementation, the push operation is implemented by incrementing the index of the top element and storing the new element at
that index. The pop operation is implemented by returning the value stored at the top index and then decrementing the index of the top element.
In a linked list-based implementation, the push operation is implemented by creating a new node with the new element and setting the next pointer of
the current top node to the new node. The pop operation is implemented by setting the next pointer of the current top node to the next node and
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
struct Stack {
int top;
unsigned capacity;
int* array;
};
{
struct Stack* stack = (struct Stack*)malloc(sizeof(struct Stack));
stack->capacity = capacity;
stack->top = -1;
return stack;
if (isFull(stack))
return;
stack->array[++stack->top] = item;
if (isEmpty(stack))
return INT_MIN;
return stack->array[stack->top--];
if (isEmpty(stack))
return INT_MIN;
return stack->array[stack->top];
int main()
push(stack1, 10);
push(stack1, 20);
push(stack1, 30);
return 0;
Output
Top element is : 20
● Easy to implement.
● It is not dynamic i.e., it doesn’t grow and shrink depending on needs at runtime. [But in case of dynamic sized arrays like vector in C++,
list in Python, ArrayList in Java, stacks can grow and shrink with array implementation as well].
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
struct StackNode {
int data;
};
stackNode->data = data;
stackNode->next = NULL;
return stackNode;
return !root;
stackNode->next = *root;
*root = stackNode;
if (isEmpty(*root))
return INT_MIN;
*root = (*root)->next;
free(temp);
return popped;
if (isEmpty(root))
return INT_MIN;
return root->data;
int main()
push(&root, 10);
push(&root, 20);
push(&root, 30);
return 0;
Output
10 pushed to stack
20 pushed to stack
30 pushed to stack
Top element is 20
Efficiency: Push and pop operations on a stack can be performed in constant time (O(1)) , providing efficient access to data.
Last-in, First-out (LIFO): Stacks follow the LIFO principle, ensuring that the last element added to the stack is the first one removed. This behavior is useful in many
specific order.
Limited capacity: Stacks have a fixed capacity, which can be a limitation if the number of elements that need to be stored is unknown or highly variable.
The way to write arithmetic expression is known as a notation. An arithmetic expression can be written in three different but equivalent notations, i.e., without changing
Infix
Prefix
Postfix
Infix notations are normal notations that are used by us while writing different mathematical expressions. The Prefix and Postfix notations are quite different.
Prefix Notation
In this notation, operator is prefixed to operands, i.e. operator is written ahead of operands. For example, +ab. This is equivalent to its infix notation a + b. Prefix notation is
To convert infix to prefix (a+b*c), we can reverse the infix expression, perform infix to postfix conversion on the reversed expression, and then reverse the resulting postfix
expression.
○ Output: c
○ Stack: (empty)
○ Output: c
○ Stack: *
○ Output: c b
○ Stack: *
○ Output: c b
○ Stack: *+
○ Output: c b a
○ Stack: *+
○ Output: c b a +
○ Stack: *
○ Output: c b a + *
○ Stack: (empty)
Prefix Expression
Postfix Notation
This notation style is known as Reversed Polish Notation. In this notation style, the operator is postfixed to the operands i.e., the operator is written after the operands. For
Example
2 (a + b) * c *+abc ab+c*
3 a * (b + c) *a+bc abc+*
5 (a + b) * (c + d) *+ab+cd ab+cd+*
Infix Expressions
Infix expressions are mathematical expressions where the operator is placed between its operands. This is the most common mathematical
notation used by humans. For example, the expression “2 + 3” is an infix expression, where the operator “+” is placed between the operands “2” and
“3”.
Infix notation is easy to read and understand for humans, but it can be difficult for computers to evaluate efficiently. This is because the order of
operations must be taken into account, and parentheses can be used to override the default order of operations.
● Infix notation is the notation that we are most familiar with. For example, the expression “2 + 3” is written in infix notation.
● In infix notation, operators are placed between the operands they operate on. For example, in the expression “2 + 3”, the addition operator
● Parentheses are used in infix notation to specify the order in which operations should be performed. For example, in the expression “(2 +
3) * 4”, the parentheses indicate that the addition operation should be performed before the multiplication operation.
Infix expressions follow operator precedence rules, which determine the order in which operators are evaluated. For example, multiplication and
division have higher precedence than addition and subtraction. This means that in the expression “2 + 3 * 4”, the multiplication operation will be
Here’s the table summarizing the operator precedence rules for common mathematical operators:
Operator Precedence
Parentheses () Highest
Exponents ^ High
Multiplication * Medium
Division / Medium
Addition + Low
Subtraction – Low
Infix expression: The expression of the form “a operator b” (a + b) i.e., when an operator is in-between every pair of operands.
Postfix expression: The expression of the form “a b operator” (ab+) i.e., When every pair of operands is followed by an operator.
Input: A + B * C + D
Output: ABC*+D+
operand, add it to the postfix expression and if we get an operator or parenthesis add it to the stack by maintaining their precedence.
● If the precedence and associativity of the scanned operator are greater than the precedence and associativity of the operator in the stack
[or the stack is empty or the stack contains a ‘(‘ ], then push it in the stack. [‘^‘ operator is right associative and other operators like ‘+‘,’–‘,’*‘ and ‘/‘
are left-associative].
1. Check especially for a condition when the operator at the top of the stack and the scanned operator both are ‘^‘. In this condition, the
precedence of the scanned operator is higher due to its right associativity. So it will be pushed into the operator stack.
2. In all the other cases when the top of the operator stack is the same as the scanned operator, then pop the operator from the stack because
of left associativity due to which the scanned operator has less precedence.
● Else, Pop all the operators from the stack which are greater than or equal to in precedence than that of the scanned operator.
1. After doing that Push the scanned operator to the stack. (If you encounter parenthesis while popping then stop there and push the scanned
5. If the scanned character is a ‘)’, pop the stack and output it until a ‘(‘ is encountered, and discard both the parenthesis.
7. Once the scanning is over, Pop the stack and add the operators in the postfix expression until it is not empty.
Parsing Expression
As we have discussed, it is not a very efficient way to design an algorithm or program to parse infix notations. Instead, these infix notations are first converted into
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int prec(char c) {
if (c == '^')
return 3;
return 2;
return 1;
else
return -1;
char associativity(char c) {
if (c == '^')
return 'R';
char result[1000];
int resultIndex = 0;
char stack[1000];
char c = s[i];
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) {
result[resultIndex++] = c;
else if (c == '(') {
stack[++stackIndex] = c;
}
// If the scanned character is an ‘)’, pop and add to the output string from the stack
else if (c == ')') {
result[resultIndex++] = stack[stackIndex--];
// If an operator is scanned
else {
|| prec(s[i]) == prec(stack[stackIndex])
result[resultIndex++] = stack[stackIndex--];
stack[++stackIndex] = c;
result[resultIndex++] = stack[stackIndex--];
result[resultIndex] = '\0';
printf("%s\n", result);
// Driver code
int main() {
// Function call
infixToPostfix(exp);
return 0;
Case - 1
To convert the infix expression a + b * c to postfix notation, we follow the Shunting Yard algorithm step by step. Here’s the detailed process:
1. Initialize:
○ Create an empty stack for operators and an empty list for the output.
○ If the token is an operand (i.e., variable or number), add it to the output list.
○ If the token is an operator, pop operators from the stack to the output list until an operator with less precedence is at the top of the stack or the stack is empty, then push
○ If the token is a right parenthesis ), pop from the stack to the output list until a left parenthesis is at the top of the stack. Remove the left parenthesis from the stack.
Step-by-Step Conversion:
1. Token: a
○ Output: a
○ Stack: []
2. Token: +
○ Output: a
○ Stack: ['+']
3. Token: b
○ Output: a b
○ Stack: ['+']
4. Token: *
○ Output: a b
5. Token: c
○ Output: a b c
6. End of expression:
○ Output: a b c * +
○ Stack: []
Postfix Expression:
The postfix notation of the given infix expression a+b*c is: abc*+
Case - 2
To convert the infix expression (a + b) * c to postfix notation, we use the Shunting Yard algorithm step by step. Here’s the detailed process:
1. Initialize:
○ Create an empty stack for operators and an empty list for the output.
○ If the token is an operand (i.e., variable or number), add it to the output list.
○ If the token is an operator, pop operators from the stack to the output list until an operator with less precedence is at the top of the stack or the stack is empty, then push the current
○ If the token is a right parenthesis ), pop from the stack to the output list until a left parenthesis is at the top of the stack. Remove the left parenthesis from the stack.
Step-by-Step Conversion:
1. Token: (
○ Output: ``
○ Stack: ['(']
2. Token: a
○ Output: a
○ Stack: ['(']
3. Token: +
○ Output: a
4. Token: b
○ Output: a b
5. Token: )
○ Output: a b +
○ Stack: []
6. Token: *
○ Output: a b +
○ Stack: ['*']
7. Token: c
○ Output: a b + c
○ Stack: ['*']
8. End of expression:
○ Output: a b + c *
○ Stack: []
Postfix Expression:
Case - 3
To convert the infix expression a + (b * (c - d) * x / y) - z to postfix notation, we will again use the Shunting Yard algorithm step by step:
Step-by-Step Conversion:
1. Initialize:
○ Create an empty stack for operators and an empty list for the output.
○ If the token is an operand (i.e., variable or number), add it to the output list.
○ If the token is an operator, pop operators from the stack to the output list until an operator with less precedence is at the top of the stack or the stack is empty, then push the current
○ If the token is a right parenthesis ), pop from the stack to the output list until a left parenthesis is at the top of the stack. Remove the left parenthesis from the stack.
Process Tokens:
1. Token: a
○ Output: a
○ Stack: []
2. Token: +
○ Output: a
○ Stack: ['+']
3. Token: (
○ Output: a
4. Token: b
○ Output: a b
5. Token: *
○ Output: a b
6. Token: (
○ Output: a b
7. Token: c
○ Output: a b c
8. Token: -
○ Output: a b c
9. Token: d
○ Output: a b c d
10. Token: )
○ Output: a b c d -
11. Token: *
○ Output: a b c d - *
12. Token: x
○ Output: a b c d - x *
13. Token: /
○ Output: a b c d - * x
14. Token: y
○ Output: a b c d - x y / *
15. Token: )
○ Output: a b c d - x y / *
16. Token: -
○ Output: a b c d - x y / * +
○ Stack: ['-']
17. Token: z
○ Output: a b c d - x y / * + z
○ Stack: ['-']
○ Output: a b c d - x y / * + z -
○ Stack: []
Postfix Expression:
Recursion means "defining a problem in terms of itself". This can be a very powerful tool in writing algorithms. Recursion comes directly from
Mathematics, where there are many examples of expressions written in terms of themselves. For example, the Fibonacci sequence is defined as: F(i)
= F(i-1) + F(i-2)
The process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function
Properties of Recursion:
Recursion has some important properties. Some of which are mentioned below:
● The primary property of recursion is the ability to solve a problem by breaking it down into smaller sub-problems, each of which can be
● A recursive function must have a base case or stopping criteria to avoid infinite recursion.
● Recursion involves calling the same function within itself, which leads to a call stack.
● Recursive functions may be less efficient than iterative solutions in terms of memory and performance.
Types of Recursion:
1. Direct recursion: When a function is called within itself directly it is called direct recursion. This can be further categorized into four
types:
● Tail recursion,
● Head recursion,
● Nested recursion.
2. Indirect recursion: Indirect recursion occurs when a function calls another function that eventually calls the original function and it
forms a cycle.
Factorial Function
5 ! = 5*4*3*2*1 =>120
n ! = 1 if n==0
#include <stdio.h>
if (n == 0)
return 1;
int main()
int num = 5;
return 0;
Fibonacci Sequence
#include <stdio.h>
int fib(int n)
if (n <= 1)
return n;
int main()
int n = 9;
return 0;
Binary Search
#include <stdio.h>
if (r >= l) {
int mid = l + (r - l) / 2;
if (arr[mid] == x)
return mid;
if (arr[mid] > x) {
// subarray
return -1;
// driver code
int main(void)
// element to be searched
int x = 10;
if (index == -1) {
else {
return 0;
Recursion in C,
A xxxxxx
A xxxxxx