0% found this document useful (0 votes)
17 views

Module 2-Stacks

Uploaded by

2022.surel.sanap
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views

Module 2-Stacks

Uploaded by

2022.surel.sanap
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 36

Module 2

Stacks
Introduction
• Stack is an important data structure which stores its elements in
an ordered manner.

• Take an analogy of a pile of plates where one plate is placed on


top of the other. A plate can be removed only from the topmost
position. Hence, you can add and remove the plate only at/from
one position, that is, the topmost position.

Another plate will The topmost plate will


be added on top of be removed first
this plate
Stacks
• A stack is a linear data structure in which the elements are added
and removed only from one end, which is called the top.
• Hence, a stack is called a LIFO (Last-In, First-Out) data structure as
the element that is inserted last is the first one to be taken out.

• Stacks can be implemented either using an array or a linked list.


Array Representation of Stacks
• In computer’s memory stacks can be represented as a linear array.
• Every stack has a variable TOP associated with it.
• TOP is used to store the address of the topmost element of the stack. It is
this position from where the element will be added or deleted.

• There is another variable MAX which will be used to store the


maximum number of elements that the stack can hold.

• If TOP = NULL, then it indicates that the stack is empty and if TOP =
MAX -1, then the stack is full.
Push Operation
• The push operation is used to insert an element in to the stack.
• The new element is added at the topmost position of the stack.
• However, before inserting the value, we must first check if
TOP=MAX-1, because if this is the case then it means the stack is
full and no more insertions can further be done.
• If an attempt is made to insert a value in a stack that is already full,
an OVERFLOW message is printed.

A B C D E

0 1 2 3 TOP = 4 5 6 7 8 9

A B C D E F

0 1 2 3 4 TOP =5 6 7 8 9
Pop Operation
• The pop operation is used to delete the topmost element from the
stack.
• However, before deleting the value, we must first check if
TOP=NULL, because if this is the case then it means the stack is
empty so no more deletions can further be done.
• If an attempt is made to delete a value from a stack that is already
empty, an UNDERFLOW message is printed.
A B C D E

0 1 2 3 TOP = 4 5 6 7 8 9

A B C D

0 1 2 TOP = 3 4 5 6 7 8 9
Peek Operation
• Peek is an operation that returns the value of the topmost
element of the stack without deleting it from the stack.
• However, the peep operation first checks if the stack is empty or
contains some elements.
• If TOP = NULL, then an appropriate message is printed else the
value is returned.

A B C D E

0 1 2 3 TOP = 4 5 6 7 8 9

Here Peep operation will return E, as it is the value of the


topmost element of the stack.
Algorithms for Push and Pop
Operations
Algorithm to PUSH an element in a stack

Step 1: IF TOP = MAX-1, then


PRINT “OVERFLOW”
Goto Step 4
[END OF IF]
Step 2: SET TOP = TOP + 1
Step 3: SET STACK[TOP] = VALUE
Step 4: END

Algorithm to POP an element from a stack

Step 1: IF TOP = NULL, then


PRINT “UNDERFLOW”
Goto Step 4
[END OF IF]
Step 2: SET VAL = STACK[TOP]
Step 3: SET TOP = TOP - 1
Step 4: END
Algorithm for Peep Operation
Algorithm for Peep Operation

Step 1: IF TOP =NULL, then


PRINT “STACK IS EMPTY”
Go TO Step 3
[END OF IF]
Step 2: RETURN STACK[TOP]
Step 3: END
Applications of Stacks
• Reversing a list

• Parentheses checker

• Conversion of an infix expression into a postfix expression

• Evaluation of a postfix expression

• Conversion of an infix expression into a prefix expression

• Evaluation of a postfix expression

• Recursion

• Tower of Hanoi
Infix Notation
• Infix, Postfix and Prefix notations are three different but
equivalent notations of writing algebraic expressions.
• While writing an arithmetic expression using infix notation, the
operator is placed between the operands. For example, A+B; here,
plus operator is placed between the two operands A and B.
• Although it is easy to write expressions using infix notation,
computers find it difficult to evaluate as they need a lot of
information to evaluate the expression.
• Information is needed about operator precedence, associativity
rules, and brackets which overrides these rules.
• So, computers work more efficiently with expressions written
using prefix and postfix notations.
Postfix Notation
• Postfix notation was given by Jan Łukasiewicz who was a Polish
logician, mathematician, and philosopher. His aim was to develop
a parenthesis-free prefix notation (also known as Polish notation)
and a postfix notation which is better known as Reverse Polish
Notation or RPN.
• In postfix notation, the operator is placed after the operands. For
example, if an expression is written as A+B in infix notation, the
same expression can be written as AB+ in postfix notation.
• The order of evaluation of a postfix expression is always from left
to right.
Postfix Notation
• The expression (A + B) * C is written as:
AB+C* in the postfix notation.

• A postfix operation does not even follow the rules of operator


precedence. The operator which occurs first in the expression is
operated first on the operands.

• For example, given a postfix notation AB+C*. While evaluation,


addition will be performed prior to multiplication.
Prefix Notation
• In a prefix notation, the operator is placed before the operands.
• For example, if A+B is an expression in infix notation, then the
corresponding expression in prefix notation is given by +AB.
• While evaluating a prefix expression, the operators are applied
to the operands that are present immediately on the right of the
operator.
• Prefix expressions also do not follow the rules of operator
precedence, associativity, and even brackets cannot alter the
order of evaluation.
• The expression (A + B) * C is written as:
*+ABC in the prefix notation
Evaluation of an Postfix Expression

Algorithm to evaluate a postfix expression

Step 1: Add a “)” at the end of the postfix expression


Step 2: Scan every character of the postfix expression and
repeat
steps 3 and 4 until “)”is encountered
Step 3: IF an operand is encountered, push it on the stack
IF an operator X is encountered, then
a. pop the top two elements from the stack as A and B
b. Evaluate B X A, where A was the topmost element and
B was the element below A.
c. Push the result of evaluation on the stack
[END OF IF]
Step 4: SET RESULT equal to the topmost element of the stack
Step 5: EXIT

Ex. 934*8+4/-
Evaluation of an Infix Expression

STEP 1: Convert the infix expression into its equivalent postfix expression

STEP2: Evaluate the postfix expression


Evaluation of an Infix Expression
STEP 1: Convert the infix expression into its equivalent postfix expression

Algorithm to convert an Infix notation into postfix notation


Step 1: Add ‘)” to the end of the infix expression
Step 2: Push “(“ on to the stack
Step 3: Repeat until each character in the infix notation is scanned
>IF a “(“ is encountered, push it on the stack
>IF an operand (whether a digit or an alphabet) is encountered,
add it to the postfix expression.
>IF a “)” is encountered, then;
a. Repeatedly pop from stack and add it to the postfix
expression until a “(” is encountered.
b. Discard the “(“. That is, remove the “(“ from stack and do
not add it to the postfix expression
>IF an operator X is encountered, then;
a Repeatedly pop from stack and add each operator (popped from the
stack) to the postfix expression which has the same precedence or
a higher precedence than X. If precedence of popped operator is
less than that of x, push popped operator back to stack.
b. Push the operator X to the stack
Step 4: Repeatedly pop from the stack and add it to the postfix expression
until the stack is empty
Step 5: EXIT

Ex: A-(B/C+(D%E*F)/G)*H
#include<stdio.h> /* define function that is used to determine whether any symbol is operator or
#include<stdlib.h> /* for exit() */ This function returns 1 if symbol is opreator else return 0 */
#include<ctype.h> /* for isdigit(char ) */
#include<string.h>
int is_operator(char symbol)
#define SIZE 100
{
char stack[SIZE]; if(symbol == '^' || symbol == '*' || symbol == '/' || symbol == '+' || symbol =='-')
int top = -1; return 1;
else
/* define push operation */ return 0;
void push(char item) }
{ if(top >= SIZE-1) }
printf("\nStack Overflow.");
else /* define fucntion that is used to assign precendence to operator.
{ * In this fucntion we assume that higher integer value * means higher precende
top = top+1;
stack[top] = item; int precedence(char symbol)
} {
} if(symbol == '^')/* exponent operator, highest precedence*/
{
return 3;
/* define pop operation */ }
char pop() else if(symbol == '*' || symbol == '/')
{ char item ; {
if(top <0) return 2;
printf("stack under flow: invalid infix }
expression"); else if(symbol == '+' || symbol == '-') /* lowest precedence */
else {
return 1;
{ item = stack[top];
}
top = top-1; else
return(item); {
} return 0;
} }
}
Void InfixToPostfix(char infix_exp[], char postfix_exp[]) else if(item == ')') /* if current symbol is ')' then */
{ int i, j; { x = pop(); /* pop and keep popping until */
char item; while(x != '(') /* '(' encounterd */
char x; {
postfix_exp[j] = x;
strcat(infix_exp,")"); /* add ')' to infix expression*/
j++;
push('('); /* push '(' onto stack */ x = pop();
}
i=0; }
j=0; else
item=infix_exp[i]; {
/* if current symbol is neither operand not '(' nor ')' and
not operator */
while(item != '\0') /* run loop till end of infix expression */
printf("\nInvalid infix Expression.\n");
{ getchar();
if(item == '(') exit(1);
push(item); }
else if( isdigit(item) || isalpha(item)) i++;
{ postfix_exp[j] = item; /* add operand symbol to postfix expr */ item = infix_exp[i]; /* go to next symbol of infix expr
j++; } /* while loop ends here */
if(top>0)
}
{
else if(is_operator(item) == 1) /* means symbol is operator */ printf("\nInvalid infix Expression.\n”);
{ }
x=pop();
while(is_operator(x) == 1 && precedence(x)>= precedence(item)) postfix_exp[j] = '\0';
{ }
postfix_exp[j] = x; /* so pop all higher precendence operator*/
j++;
x = pop(); /* add them to postfix expression */
}
push(x);
push(item); /* push current operator symbol onto stack */
}
/* main function */

int main()
{
char infix[SIZE], postfix[SIZE]; /* declare infix string and postfix string */

printf("\nEnter Infix expression : ");


gets(infix);

InfixToPostfix(infix,postfix); /* call to convert */


printf("Postfix Expression: ");
puts(postfix); /* print postfix expression */

return 0;
}
Evaluation of an Infix Expression
STEP 2: Evaluate the postfix expression

Algorithm to evaluate a postfix expression

Step 1: Add a “)” at the end of the postfix expression


Step 2: Scan every character of the postfix expression and repeat
steps 3 and 4 until “)”is encountered
Step 3: IF an operand is encountered, push it on the stack
IF an operator X is encountered, then
a. pop the top two elements from the stack as A and B
b. Evaluate B X A, where A was the topmost element and B was
the element below A.
c. Push the result of evaluation on the stack
[END OF IF]
Step 4: SET RESULT equal to the topmost element of the stack
Step 5: EXIT
Convert Infix Expression into Prefix
Expression
• Step 1: Reverse the infix string. Note that while reversing the string
you must interchange left and right parenthesis.

• Step 2: Obtain the corresponding postfix expression of the infix


expression obtained as a result of Step 1.

• Step 3: Reverse the postfix expression to get the prefix expression

Ex. (A – B / C) * (A / K – L)
Evaluation of an Prefix Expression

Algorithm to evaluate a prefix expression

Step 1: Accept the Prefix expression


Step 2: Repeat until all characters in the prefix expression are
scanned
a. Scan the prefix expression from right,one charcter at
time
b. If an operand is encountered, push it on the stack
c. If an operator X is encountered, then
a. pop the top two elements from the stack as A and B
b. Evaluate B X A, where A was the topmost element and
B was the element below A.
c. Push the result of evaluation on the stack
[END OF IF]
Step 4: SET RESULT equal to the topmost element of the stack
Step 5: EXIT

Ex. +-27*8/48
Evaluation of Prefix Expression
• Step 1: Reverse the infix string. Note that while reversing the string
you must interchange left and right parenthesis.

• Step 2: Obtain the corresponding postfix expression of the infix


expression obtained as a result of Step 1.

• Step 3: Reverse the postfix expression to get the prefix expression

Ex. (A – B / C) * (A / K – L)
Recursion
• Recursion is an implicit application of STACK ADT.
• A recursive function is a function that calls itself to solve a smaller
version of its task until a final call is made which does not require a
call to itself.
• Every recursive solution has two major cases: the base case in
which the problem is simple enough to be solved directly without
making any further calls to the same function.
• Recursive case, in which first the problem at hand is divided into
simpler subparts. Second the function calls itself but with subparts
of the problem obtained in the first step. Third, the result is
obtained by combining the solutions of simpler sub-parts.
Types of Recursion
• Any recursive function can be characterized based on:
▪ whether the function calls itself directly or indirectly (direct or
indirect recursion).
▪ whether any operation is pending at each recursive call (tail-
recursive or not).
▪ the structure of the calling pattern (linear or tree-recursive).

Recursion

Direc Indire Line Tre


Tail
t ct ar e
Direct Recursion
• A function is said to be directly recursive if it explicitly calls itself.
• For example, consider the function given below.

int Func( int n)


{
if(n==0)
retrun n;
return (Func(n-1));
}
Indirect Recursion
• A function is said to be indirectly recursive if it contains a call to
another function which ultimately calls it.
• Look at the functions given below. These two functions are
indirectly recursive as they both call each other.

int Func1(int n) int Func2(int x)


{ {
if(n==0) return Func1(x-1);
return n; }
return Func2(n);
}
Linear Recursion
• Recursive functions can also be characterized depending on the
way in which the recursion grows: in a linear fashion or forming a
tree structure.
• In simple words, a recursive function is said to be linearly recursive
when no pending operation involves another recursive call to the
function.
• For example, the factorial function is linearly recursive as the
pending operation involves only multiplication to be performed
and does not involve another call to fact() function.
Tree Recursion
• A recursive function is said to be tree recursive (or non-linearly
recursive) if the pending operation makes another recursive call to
the function.
• For example, the Fibonacci function Fib in which the pending
operations recursively calls the Fib function.

int Fibonacci(int num)


{
if(num <= 2)
return 1;
return ( Fibonacci (num - 1) + Fibonacci(num – 2));
}
Tail Recursion
• A recursive function is said to be tail recursive if no operations are
pending to be performed when the recursive function returns to
its caller.
• That is, when the called function returns, the returned value is
immediately returned from the calling function.
• Tail recursive functions are highly desirable because they are much
more efficient to use as in their case, the amount of information
that has to be stored on the system stack is independent of the
number of recursive calls.
int Fact(n) int Fact1(int n, int res)
{ {
return Fact1(n, 1); if (n==1)
} return res;
return Fact1(n-1, n*res);
}
Fibonacci Series
• The Fibonacci series can be given as:
0 1 1 2 3 5 8 13 21 34 55……
• That is, the third term of the series is the sum of the first and
second terms. Similarly, fourth term is the sum of second and third
terms, so on and so forth.
• A recursive solution to find the nth term of the Fibonacci series can
be given as:
FIB(n) = 1, if n<=2

FIB (n - 1) + FIB (n - 2), otherwise FIB(7)

FIB(6) FIB(5)

FIB(5) FIB(4) FIB(4) FIB(3)

FIB(4) FIB(3) FIB(3) FIB(2) FIB(3) FIB(2) FIB(2) FIB(1)

FIB(3) FIB(2) FIB(2) FIB(1) FIB(2) FIB(1) FIB(2) FIB(1)

FIB(2) FIB(1)
Pros and Cons of Recursion
Pros
• Recursive solutions often tend to be shorter and simpler than non-
recursive ones.
• Code is clearer and easier to use.
• Follows a divide and conquer technique to solve problems.
• In some (limited) instances, recursion may be more efficient.
Cons
• For some programmers and readers, recursion is a difficult
concept.
• Recursion is implemented using system stack. If the stack space on
the system is limited, recursion to a deeper level will be difficult to
implement.
• Aborting a recursive process in midstream is slow.
• Using a recursive function takes more memory and time to
execute as compared to its non-recursive counterpart.
• It is difficult to find bugs, particularly when using global variables.
Tower of Hanoi
Tower of Hanoi is one of the main applications of a recursion. It says, "if you can solve
n-1 cases, then you can easily solve the nth case"

A B C A B C

If there is only one ring, then simply move the ring from source to the destination

A B C
A B C A B C

If there are two rings, then first move ring 1 to the


spare pole and then move ring 2 from source to the
destination. Finally move ring 1 from the source to the
A B C
destination
Tower of Hanoi
Consider the working with three rings.

A B C
A B C
A B C

A B C A B C
A B C

A B C A B C
C recursive function to solve tower of hanoi puzzle

void towerOfHanoi(int n, char from_rod, char to_rod, char aux_rod)


{
if (n == 1)
{
printf("\n Move disk 1 from rod %c to rod %c", from_rod, to_rod);
return;
}
towerOfHanoi(n-1, from_rod, aux_rod, to_rod);
printf("\n Move disk %d from rod %c to rod %c", n, from_rod, to_rod);
towerOfHanoi(n-1, aux_rod, to_rod, from_rod);
}

int main()
{
int n = 4; // Number of disks
towerOfHanoi(n, 'A', 'C', 'B'); // A, B and C are names of rods
return 0;
}

You might also like