DS Module2 Notes
DS Module2 Notes
MODULE-2
STACKS AND QUEUES
TOPICS
Stacks: Definition, Stack Operations, Array Representation of Stacks, Stacks using Dynamic Arrays,
Stack Applications: Polish notation, Infix to postfix conversion, evaluation of postfix expression.
STACK
“Stack is an ordered collection of elements or items of same type can be inserted and deleted at only
one end called Top of stack”. (OR)
STACK is an ordered-list in which insertions (called push) and deletions (called pop) are
made at one end called the top. Since last element inserted into a stack is first element removed, a
stack is also known as a LIFO list (Last In First Out). Stack can be implemented using the Linked List
or Array.
Stack belongs to non-primitive linear data structure.
Consider a stack s=(a0,a1,….,an-1).here a0 is the bottom element , an-1 is the top element and
generally, element ai is on the top of element ai-1,0<i<n.
Top an-1
an-2
…..
….
a1
a0
Figure 1a: Stack S
If A, B, C, D, E are the elements added into stack in that order then E is the first element to be
deleted. Figure shows insertion and deletion of elements from the stack.
Page 1
Data structures and Applications 18CS32
Thus, Stack is LIFO Structure i,e Last in First Out as shown in figure 1. Example, we can place or
remove a card or plate from top of the stack only.
Page 2
Data structures and Applications 18CS32
• If one function invokes another function, local variables and parameters of the invoking-function are
added to its stack-frame.
• A new stack-frame is then created for the invoked-function & placed on top of the system-stack.
• When this function terminates, its stack-frame is removed (and processing of the invoking-function,
which is again on top of the stack, continues).
• Frame-pointer(fp) is a pointer to the current stack-frame.
Page 3
Data structures and Applications 18CS32
Page 4
Data structures and Applications 18CS32
POP Operation
Accessing the content while removing it from stack, is known as pop operation. In array
implementation of pop() operation, data element is not actually removed, instead top is decremented to a
lower position in stack to point to next value. But in linked-list implementation, pop() actually removes
data element and deallocates memory space. Pop operation is shown in figure6.
A POP operation may involve the following steps −
Step 1 − Check if stack is empty.
Step 2 − If stack is empty, produce error and exit.
Step 3 − If stack is not empty, access the data element at which top is pointing.
Step 4 − Decrease the value of top by 1.
Step 5 − return success.
Page 5
Data structures and Applications 18CS32
Function push/add() checks to see if the stack is full. If it is, it calls stack_full(), which prints an
error message and terminates execution. When the stack is not full, we increment top and assign item to
stack[top].
Function pop/delete() checks to see if the stack is empty using top . If top reaches -1,then it
calls stack_empty(), which prints an error message and terminates execution. When the stack is not
empty, we return the top most element stack[top] and decrement top.
void stack_full()
{ printf(stderr,”stack is full, can‟t add element”);
exit(EXIT_FAILURE);
}
void stack_empty ()
{ printf(stderr,”stack is empty, can‟t delete element”);
exit(EXIT_FAILURE);
}
Page 6
Data structures and Applications 18CS32
void stack_full()
{ printf(stderr,”stack is full, can‟t add element”);
exit(EXIT_FAILURE);
}
void stack_empty ()
{ printf(stderr,”stack is empty, can‟t delete element”);
exit(EXIT_FAILURE);
}
Once the stack is full, realloc() function is used to increase the size of [Link] array-doubling,
we double array-capacity whenever it becomes necessary to increase the capacity of an array.
ANALYSIS
In worst case, the realloc function needs to allocate 2*capacity*sizeof(*stack) bytes of memory
and copy capacity*sizeof(*stack) bytes of memory from the old array into the new one. The total time
Page 7
Data structures and Applications 18CS32
spent over all array doublings = O(2k) where capacity=2k. Since the total number of pushes is more than
2k-1, the total time spend in array doubling is O(n) where n=total number of pushes.
Page 8
Data structures and Applications 18CS32
Page 9
Data structures and Applications 18CS32
Example 1:
Convert ((A – (B + C)) * D) ↑ (E + F) infix expression to postfix form:
Page 10
Data structures and Applications 18CS32
Example 2:
Convert the following infix expression A + B * C – D / E * H into its equivalent postfix expression
Page 11
Data structures and Applications 18CS32
Example 1:
Evaluate the postfix expression: 6 5 2 3 + 8 * + 3 + *
2.5 RECURSION
Recursion is the process of repeating items in a self-similar way. In programming languages, if a
program allows you to call a function inside the same function, then it is called a recursive call of the
function.
Page 12
Data structures and Applications 18CS32
void recursion()
{
recursion(); /* function calls itself */
}
void main()
{
recursion();
}
The C programming language supports recursion, i.e., a function to call itself.
A recursive function is a function that calls itself during its execution.
But while using recursion, programmers need to be careful to define an exit condition from the function;
otherwise it will go into an infinite loop.
Recursive functions are very useful to solve many mathematical problems, such as calculating the
factorial of a number, generating Fibonacci series, etc.
RECURSION PROPERTIES
A recursive function can go infinite like a loop. To avoid infinite running of recursive function,
there are two properties that a recursive function must have −
Base criteria − There must be at least one base criteria or condition, such that, when this
condition is met the function stops calling itself recursively.
Recursive criteria − the recursive calls should progress in such a way that each time a recursive
call is made it comes closer to the base criteria.
1. FACTORIAL NUMBER
The product of the positive integers from 1 to n, inclusive is called n factorial and is usually
denoted by n!
n!=1*2*3*4*………*(n-2)*(n-1)*n.
Factorial function may be defined as
a. if n=0 then return 1
b. if n>0, then return n*(n-1)!
The following example calculates the factorial of a given number using a recursive function
#include <stdio.h>
int factorial(unsigned int n)
{
if(n <= 1)
{
return 1;
}
return n * factorial(n - 1);
}
Page 13
Data structures and Applications 18CS32
void main()
{
int n,res;
printf(“\n enter the value for n”);
scanf(“%d”,&n);
res=factorial(n);
printf("Factorial of %d is %d\n", n, res);
}
When the above code is compiled and executed, it produces the following result − Factorial of 15 is
2004310016
Page 14
Data structures and Applications 18CS32
3. FIBONACCI SERIES
The Fibonacci sequence is the sequence of integers, where each number in this sequence is the
sum of two preceding elements.
A formal definition is
a. If n=0 or 1,return n(0/1)
b. If n>1,return fib(n-1)+fib(n-2)
#include <stdio.h>
int fib(int i)
{
if(i == 0)
{
return 0;
}
if(i == 1)
{
return 1;
}
return (fib(i-1) + fib(i-2));
}
void main()
{
int i;
for (i = 0; i < 10; i++)
{
printf("%d\t", fib(i));
}
}
When the above code is compiled and executed, it produces the following result −
0 1 1 2 3 5 8 13 21 34
Page 15
Data structures and Applications 18CS32
These rings are of different sizes and stacked upon in ascending order i.e. the smaller one sits
over the larger one. There are other variations of puzzle where the number of disks increase, but the
tower count remains the same.
Rules
The mission is to move all the disks to some another tower without violating the sequence of
arrangement. The below mentioned are few rules which are to be followed for tower of hanoi −
Only one disk can be moved among the towers at any given time.
Only the "top" disk can be removed.
No large disk can sit over a small disk.
Here is an animated representation in figure 8 of solving a tower of hanoi puzzle with three disks
−Tower of hanoi puzzle with n disks can be solved in minimum 2n−1 steps. This presentation shows
that a puzzle with 3 disks has taken 23−1 = 7 steps.
Algorithm
To write an algorithm for Tower of Hanoi, first we need to learn how to solve this problem with lesser
amount of disks, say → 1 or 2. We mark three towers with name, source, destination and aux (only to
help moving disks). If we have only one disk, then it can easily be moved from source to destination
peg.
If we have 2 disks −
First we move the smaller one (top) disk to aux peg
Then we move the larger one (bottom) disk to destination peg
And finally, we move the smaller one from aux to destination peg.
So now we are in a position to design algorithm for Tower of Hanoi with more than two disks. We
divide the stack of disks in two parts. The largest disk (nthdisk) is in one part and all other (n-1) disks
are in second part. Our ultimate aim is to move disk n from source to destination and then put all other
(n-1) disks onto it. Now we can imagine to apply the same in recursive way for all given set of disks.
So steps to follow are −
Step 1 − Move n-1 disks from source to aux
Step 2 − Move nth disk from source to dest
Step 3 − Move n-1 disks from aux to dest
A recursive algorithm for Tower of Hanoi can be driven as follows −
START
Procedure tower(disk, source, dest, aux)
if n == 1, THEN
move disk from source to dest
Page 16
Data structures and Applications 18CS32
else
tower(n - 1, source, aux, dest) // Step 1
move disk from source to dest // Step 2
tower(n - 1, aux, dest, source) // Step 3
END IF
END Procedure
STOP
PROGRAM:
#include<stdio.h>
#include<conio.h>
#include <stdio.h>
void towers(int, char, char, char);
int main()
{
int num;
printf("Enter the number of disks : ");
scanf("%d", &num);
printf("The sequence of moves involved in the Tower of Hanoi are :\n");
towers(num, 'A', 'C', 'B');
getch();
return 0;
}
void towers(int num, char source, char dest, char aux)
{
if (num == 1)
{
printf("\n Move disk 1 from peg %c to peg %c", source,dest);
return;
}
towers(num - 1, source, aux,dest);
printf("\n Move disk %d from peg %c to peg %c", num, source, dest);
towers(num - 1, aux, dest, source);
}
The below figure shows the disks movements in tower of Hanoi for 3 disks
Page 17
Data structures and Applications 18CS32
The below figure shows the recursive function calls in tower of Hanoi for 3 disks
ACKERMANN'S FUNCTION
Ackermann–Péter function, is defined as follows for nonnegative integers m and n:
Page 18
Data structures and Applications 18CS32
{
int m,n;
printf(“Enter the value of m and n\n”);
scanf(“%d %d”,&m,&n);
printf(“%d”,ackerman(m,n));
}
2.6 QUEUES
Queue is an ordered-list in which insertions & deletions take place at different ends. The end at
which new elements are added is called the rear &the end from which old elements are deleted is called
the front. Since first element inserted into a queue is first element removed, queues are known as FIFO
lists.
(OR)
Queue is an abstract data structure, somewhat similar to Stack. In contrast to Queue, queue is opened at
both ends. One end is always used to insert data (enqueue) and the other is used to remove data
(dequeue). Queue follows First-In-First-Out methodology, i.e., the data item stored first will be accessed
first.(as shown in figure 9)
Page 19
Data structures and Applications 18CS32
ADT QUEUE
ADT:-QUEUE
APPLICATIONS OF QUEUE
Queue, as the name suggests is used whenever we need to have any group of objects in an order in
which the first one coming in, also gets out first while the others wait for there turn, like in the following
scenarios :
1. Serving requests on a single shared resource, like a printer, CPU task scheduling etc.
2. In real life, Call Center phone systems will use Queues, to hold people calling them in an order, until
a service representative is free.
3. Handling of interrupts in real-time systems. The interrupts are handled in the same order as they
arrive, First come first served
2.7 QUEUE BASIC OPERATIONS
Queue operations may involve initializing or defining the queue, utilizing it and then completing erasing
it from memory. Here we shall try to understand basic operations associated with queues −
enqueue() − add (store) an item to the queue.
Page 20
Data structures and Applications 18CS32
Few more functions are required to make above mentioned queue operation efficient. These are −
peek() − get the element at front of the queue without removing it.
In queue, we always dequeue (or access) data, pointed by front pointer and while enqueing (or storing)
data in queue we take help of rear pointer.
peek() Like Queues, this function helps to see the data at the front of the queue. Code for the peek()
function −
int peek()
{
return queue[front];
}
isfull()
As we are using single dimension array to implement queue, we just check for the rear pointer to reach
at MAXSIZE to determine that queue is full. In case we maintain queue in a circular linked-list, the
algorithm will differ. Implementation of isfull() function in C programming language −
bool isfull()
{
if(rear == MAXSIZE - 1)
return true;
else
return false;
}
isempty()
Here's the C programming code −
bool isempty()
{
if(front < 0 || front > rear)
return true;
else
return false;
}
Enqueue (Insert) Operation
As queue maintains two data pointers, front and rear, its operations are comparatively more difficult to
implement than Queue.(as shown in figure 12)
The following steps should be taken to enqueue (insert) data into a queue −
Step 1 − Check if queue is full.
Page 21
Data structures and Applications 18CS32
Step 3 − If queue is not full, increment rear pointer to point next empty space.
Step 4 − Add data element to the queue location, where rear is pointing.
Page 22
Data structures and Applications 18CS32
JOB SCHEDULING
Queues are used for the creation of a job-queue by an operating-system (Figure 14). If operating-system
does not use, then the jobs are processed in the order they enter the system.
Page 23
Data structures and Applications 18CS32
a. shifting the jobs as the job leaves the queue and recalculating front and rear values, but shifting is very
time consuming b. another solution to the above problem is using circular queue.
2.8 CIRCULAR QUEUE
Circular queue is a linear data structure. It follows FIFO principle. In circular queue the last node is
connected back to the first node to make a circle. Circular linked list follow the First In First Out
principle.(as shown in figure 15) Elements are added at the rear end and the elements are deleted at front
end of the queue. The queue is considered as a circular queue when the positions 0 and MAX-1 are
adjacent. Any position before front is also after rear.
A circular queue looks like
Page 24
Data structures and Applications 18CS32
This shortcoming can be overcome by using a dynamically allocated array for the elements & then
increasing the size of the array as needed. In array-doubling, double array-capacity is used whenever it
becomes necessary to increase the capacity of an array (Figure 16). [ Program A and Program B contains
code for circular array implementation using dynamic array]
Program A: Addition operation on CQ
void addq(element item)
{
rear= (rear+1) % capacity;
if(front == rear)
queueFull();
queue[rear]=item;
}
Page 25
Data structures and Applications 18CS32
2.10 DEQUEUES
The word dequeue is short form of double ended queue. In a dequeue, insertion as well as deletion can
be carried out either at the rear end or the front end.(as shown in figure 17)
Operations on a Dequeue
initialize(): Make the queue empty
Page 26
Data structures and Applications 18CS32
An output-restricted dequeue is one where insertion can be made at both ends, but deletion can
be made from one end only.
Both the basic and most common list types in computing, queues and stacks can be considered
specializations of dequeues, and can be implemented using deques.
2.11 PRIORITY QUEUE
Priority Queue is more specialized data structure than Queue. Like ordinary queue, priority queue has
same method but with a major difference. In Priority queue items are ordered by key value so that item
with the lowest value of key is at front and item with the highest value of key is at rear or vice versa. So
we're assigned priority to item based on its key value. Lower the value, higher the priority. Following
are the principal methods of a Priority Queue.(as shown in figure 18)
Basic Operations
insert / enqueue − add an item to the rear of the queue.
remove / dequeue − remove an item from the front of the queue.
Representations of priority queue
1. Priority Queue array Representation
Page 27
Data structures and Applications 18CS32
Page 28
Data structures and Applications 18CS32
2. Algorithm that adds an item with priority number N to a priority queue which is maintained in
memory as a one-way list.
1. Traverse the one-way list until finding a node X, whose priority number exceeds N. Insert
ITEM in front of node X.
2. If no such node is found , insert ITEM as the last element of the list.
Page 29
Data structures and Applications 18CS32
The rat starts at the top left and is to exit at the bottom right. With the maze represented as 2D array,
the location of the rat in the maze can at any time be described by the row and column position,
If X is the spot of our current position, maze[row][col]. Following figure represents the possible
moves from this position. It points to specify the 8 directions of movements:- N, NE, E, SE, S, SW,
W, NW as shown.
The border conditions of the maze can be represented by a border of ones. Thus, an mxp maze will
require an (m+2)x(p+2) array. The entrance is at position[1][1] and exit at [m][p].
N[i‐1][j]
NW[i‐1][j‐1] NE[i‐1][j+1]
W[i][j‐1] E[i][j+1]
[i][j]
SE[i+1][j+1]
SW[i+1][j‐1] S[i+1][j]
Figure 23: Allowable moves
The possible directions of movement can be predefined in the move array as shown in following
table. The 8 possible directions of movement are given by 0 to 7.
typedef struct
{
short int vert;
short int horiz;
Page 30
Data structures and Applications 18CS32
}offsets;
offsets moves[8];
If the rat is at position maze[row][col] and the next move position can be obtained as follows:-
By saving the current position, it is possible to return to it back and try another path if it is a hopeless
path.
Thus, all possible moved starting from the north and moving clockwise are examined.
Initial maze traversal is shown in the above Figure. EXIT_ROW & EXIT_COL gives the
coordinates of maze exit.
When searching the maze from entrance to exit, all positions with 0 will be on the stack when the
exit is reached.
Since, an mxp maze can have at most mp zeros, it is sufficient for the stack to have this capacity.
Page 31
Data structures and Applications 18CS32
The function uses a variable found that is initially set to 0 (FALSE). If we find a path through the
maze, then set this variable to TRUE, thereby allowing to exit both while loops.
Page 32
Data structures and Applications 18CS32
mark[nextRow][nextCol] = 1;
[Link] = row;
[Link] = col;
[Link] = ++dir;
push(position);
row=nextRow;
col=nextCol;
dir=0;
}
else ++dir;
}
}
if(found)
{
printf(“the path is:\n”);
printf(“row col\n”);
for(i=0;i<=top;i++)
printf(“%2d %5d\n”, stack[i].row, stack[i].col);
printf(“%2d %5d\n”, row, col);
printf(“%2d %5d\n”, EXIT_ROW, EXIT_COL);
}
else
printf(“The maze doesnot have a path”);
}
Page 33
Data structures and Applications 18CS32
Figure 25 :configuration when stack I meets stack i+1,but the memory is not full
In push function, top[i]==boundary[i+1] condition implies only that a particular stack ran out of
memory, not that the entire memory is full.(In fact, there may be a lot of unused space between other
stacks in array memory).(as shown in figure 24).Therefore, an error recovery function is created,
stackFull, which determines if there is any free space in memory. If there is space available, it should
shift the stacks so that space is allocated to the full stack. We can guarantee that stackFull adds elements
as long as there is free space in array memory if we:
1) Determine the least j, i<j<n such that there is free space between stacks j and j+1 i.e.
top[j]<boundary[j+1]. If there is such a j, then move stacks i+1,i+2 . . . . . .j one position to the right.
This creates a space between stacks i and i+1.
2) If there is no j as in (i),then look to the left of stack i. Find the largest j such that 0<=j<I and there is
space between stacks j and j+1 i.e. top[j]<boundary[j+1]. If there is such a j, then move stacks j+1,j+2. .
. . . .i one space to the left. This also creates a space between stacks I and i+1.
3) If there is no j satisfying either (i) or (ii),then all MEMORY_SIZE spaces of memory utilized and
there is no free space. In this case, stackFull terminates with an error message.
----------------------Module2----------------------------
Data structures and Applications 18CS32