DSA2
DSA2
RECURSION
2
DEFINITION OF RECURSION
“Recursion is a process in which a function calls itself directly or indirectly.”
For Example:
int fun()
{
//Here fun() is calling Itself
…….
fun();
}
fun(3)=3
int fun(int n) fun(3)
{
if (n==1) return 1 + fun(n-1) return 1 + 2=3
return 1; means fun(2)
else return 1 +1=2
return 1+fun(n-1); return 1 + fun(n-1)
} means fun(1)
int main() return 1;
return 1;
{
int n=3; Returning back to the caller
printf(“%d”, fun(n));
return 0;
}
Output: 3
4
What is the output ?
int fun(int n)
a) 2
{ b) 4
if (n==0) c) 15
return 1; d) 8
else
return 7+fun(n-2);
}
int main()
{
int n=4;
printf(“%d”, fun(n));
return 0;
}
5
HOW TO WRITE RECURSIVE FUNCTIONS:
1. Divide the problem into smaller sub-problems.
2. Specify the base condition to stop the recursion.
Ex:
Calculate Fact(4)
Fact(1)=1
Fact(2)=2*1= 2*Fact(1)
Fact(3)=3*2*1= 3*Fact(2)
Fact(4)=4*3*2*1= 4*Fact(3)
Fact(n)=n* Fact(n-1)
6
Specify the base condition to stop the recursion:
• This is the termination condition that tells the function when to stop calling itself
recursively.
• It's essentially a condition that can be evaluated directly without needing further
recursion.
• Without a base case, a recursive function would call itself indefinitely, leading to a stack
overflow error.
Ex:
int fact(int n)
{
if(n==1) Base case 2
return 1;
else
return n*fact(n-1); Recursive 1
} procedure
7
Factorial program with tracing:
Step1: n=4 Result =fact(24)
#include<stdio.h> fact(4)
if(4==1) #False
int fact(int n)
else
{ return 4*fact(3)=4*6=24
if(n==1) Step2:n=3
fact(3)
return 1;
if(3==1) #False
else else
return n*fact(n-1); return 3*fact(2) =3*2=6
Step3: n=2
}
fact(2)
int main() if(2==1) #False
{ else
return 2*fact(1) =2*1=2
int n;
Step4: n=1
printf("enter the number:"); fact(1)
scanf("%d",&n); if(1==1) #True
return 1
printf("Fcatorial of %d is %d",n,fact(n));
} 8
TYPES OF RECURSION
1. Direct recursion
2. Indirect recursion
3. Tail recursion
4. Non-tail recursion
In direct recursion, a function calls itself directly within its own definition
Ex:
int fun()
{
…….
fun();
}
In indirect recursion, two or more functions call each other in a circular manner. it means A function (fun)
is called indirect recursive if it calls another function (fun2) and then fun2 calls fun directly or indirectly
9
Ex: fun() fun2()
{ {
//some code //some code
fun2(); fun();
//some code // some code
} }
Write a program to print numbers from 1 to 10 in such a way that when number is odd, add 1 and when
number is even ,subtract 1
void even()
void odd(); {
void even(); if(n<=10)
int n=1; {
void odd() printf(“%d”,n-1);
{ n++;
if(n<=10) odd();
{ }
printf(“%d”,n+1); return;
}
n++;
int main()
even();
{
}
odd();
return;
}
} 10
Tail recursion: A recursive function is said to be tail- Non-tail recursion :A recursive function is said to be
recursive if the recursive call is the last thing done by non-tail-recursive if the recursive call is not the last
the function. There is no need to keep record of the thing done by the function. After returning back, there is
previous state something left to evaluate.
Ex: Ex:
void fun(int n) void fun(int n)
{ {
if(n==0) if(n==0)
return ; return ;
else fun(n-1);
printf(“%d”, n); printf(“%d”, n);
return fun(n-1); }
} int main()
int main() {
{ fun(3);
fun(3); return 0;
return 0; }
}
Output: 123
Output: 321
11
GCD program with tracing:
#include <stdio.h>
int gcd(int a, int b) Step 1:gcd(48, 18)
{ i.e. a=48, b=18
if (b == 0) if(18==0) False
{ (b, a % b)=> (18, 48 % 18 =12)
return a; // Base case Step 2: gcd(18, 12)
} i.e. a=18, b=12
else
if(12==0) False
{
return gcd(b, a % b);
(b, a % b)=>(12, 18 % 12 =6)
} Step 3: gcd(12, 6)
} i.e. a=12, b=6
int main() if(6==0) False
{ (b, a % b)=> (6,12 % 6 =0)
int num1, num2; Step 4: gcd(6, 0)
printf("Enter two integers: "); i.e. a=6, b=0
scanf("%d %d", &num1, &num2); if(0==0) True (return a)
int result = gcd(num1, num2);
(b, a % b)=>(0, 6 % 0 = 6)
printf("The GCD of %d and %d is %d\n", num1, num2, result);
return 0;
// Step 5: gcd(0, 6)
} => return 6 (since b == 0)
12
Fibonacci Sequence with tracing
#include <stdio.h> ( next term is obtained by taking sum of previous two terms)
int fib(int n)
{ Step 1: i=0; 0<6 Step 5:i=4; 4<6
if (n <= 1) fib(i)=fib(0) fib(i)=fib(4)
{ i=n=0 i=n=4
return n; if(0<=1) #True Result = 0 if(4<=1) #Flase
} else { Step 2: i=1; 1<6 else fib(n-1)+fib(n-2)
return fib(n - 1) + fib(n - 2); fib(i)=fib(1) fib(3) + fib(2) =2+1= 3
} i=n=1 Result = 3
} if(1<=1) #True Result = 1 Step 6:i=5; 5<6
int main() Step 3:i=2; 2<6 fib(i)=fib(5)
{ fib(i)=fib(2) i=n=5
int num; i=n=2 if(5<=1) #Flase
printf("Enter the number of terms: "); if(2<=1) #Flase else fib(n-1)+fib(n-2)
scanf("%d", &num); //num =6 else fib(n-1)+fib(n-2) fib(4) + fib(3) =3+2= 5
printf("Fibonacci Series: "); fib(1) + fib(0) =1+0= 1 Result = 1 Result = 5
for (int i = 0; i < num; ++i) Step 4:i=3; 3<6 Step 7:i=6 ;6<6 #False
{ fib(i)=fib(3)
printf("%d ", fib(i)); i=n=3
} if(3<=1) #Flase
printf("\n"); else fib(n-1)+fib(n-2)
return 0; fib(2) + fib(1) =1+1= 2 Result = 2 13
}
Tower of Hanoi Problem
In the problem of Tower of Hanoi, there will be three poles, viz. A, B and C. Pole A (source pole) contains
‘n’ discs of different diameters and are placed one above the other such that larger disc is placed below the
smaller disc. Now, all the discs from source (A) must be transferred to destination (C) using the pole B as
temporary storage.
Conditions are:
Only one disc must be moved at a time
smaller disc is on the top of larger disc at every step
Tower ( 2 A C B) if
(2==1) F
Move disc 2 from A to B count =2
Tower ( n-1,t,s,d)
Tower ( 1 C A B)
if(1==1) T
Move disc 1 from C to B count =3
Tower ( 3 A B C) if
(3==1) F
Move disc 3 from A to C count =4
Tower ( n-1,t,s,d)
17
Tower ( 2 B A C) if
What is Abstract data types?
In computer science, an abstract data type (ADT) is basically a blueprint
for how data should be handled. It defines the data that can be stored and the
operations that can be performed on that data, without going into the specifics of
how the data is actually stored in memory.
Some common examples of abstract data types : Stack ,Queues ,List etc.
18
Queue
Definition:
Queue is also an abstract data type or a linear
data structure in which insertions are done at one end
(rear/tail) and deletions are done at other
end(front/head).The first element to be inserted is the
first one to be deleted . Hence, it is called First in First
out (FIFO) or Last in Last out(LILO).
21
Applications of Queues
Process scheduling in operating systems: Operating systems use queues to manage processes
waiting for CPU resources.
Breadth-first search (BFS) algorithm: Queues are essential for traversing graphs and trees level by
level.
Level order traversal in trees: Similar to BFS, level order traversal in trees visits nodes level by
level.
Implementing FIFO buffers: Queues excel at maintaining the order of elements
Task management systems: Queues are perfect for managing a sequence of tasks
Real-time systems (e.g., handling network traffic)
22
Queue Representation
Using Array
Queues can be easily represented using linear arrays.
Every queue has front and rear variables that point to the position from where
deletions and insertions can be done, respectively.
20XX 23
Note: An attempt to insert an element into a full queue is called as Queue overflow.
Trying to delete an element from an empty queue is known as Queue underflow.
24
Queue using Linked list:
If we implement the queue using an array, we need to specify the array size at the beginning(at
compile time).
We can't change the size of an array at runtime. So, the queue will only work for a fixed number of elements.
Solution:
• We can implement the queue data structure using the linked list.
• In the linked list, we can change its size at runtime.
25
Queue Variants
Linear Queue:
• Linear queues are the simplest type of queues, where elements are stored in a linear manner.
• They follow the First In First Out (FIFO) principle.
• Linear queues can be implemented using arrays or linked lists.
• In linear queues, both enqueue (addition) and dequeue (removal) operations occur at opposite ends of the
queue.
Circular Queue:
• Circular queues are similar to linear queues but with the added feature of wrapping around when the rear or
front reaches the end of the queue.
• This allows efficient utilization of memory space and avoids wastage of space.
• Circular queues can also be implemented using arrays or linked lists.
• They are particularly useful in scenarios where a fixed-size buffer is needed, such as in operating systems
for managing processes or in networking for managing data packets.
26
Priority Queue:
• Priority queues are queues where each element has an associated priority.
• Elements with higher priority are dequeued before elements with lower priority, regardless of the
order in which they were enqueued.
• Priority queues can be implemented using various data structures like heaps, binary search trees, or
arrays.
• They are used in various applications like task scheduling, Dijkstra's algorithm for shortest path
finding, etc.
• A double-ended queue, or deque, is a queue where elements can be added or removed from both
ends.
• It supports operations like enqueue and dequeue from both front and rear ends.
• Deques can be implemented using arrays or linked lists with pointers to both ends.
• They are useful in scenarios where elements need to be added or removed from both ends efficiently,
such as implementing a queue in a concurrent environment.
27
Circular queue
A circular queue is an extended version of a linear queue as it follows the First In First Out principle with
the exception that it connects the last node of a queue to its first by forming a circular link.
• The last node is connected to the first node.
• Also known as a Ring Buffer, the nodes are connected end to end.
• Insertion takes place at the front of the queue, and deletion at the end of the queue
Operations:
Front - Used to get the starting element of
the Circular Queue.
Rear - Used to get the end element of the
Circular Queue.
enQueue(value) - Used to insert a new
value in the Circular Queue. This operation
takes place from the end of the Queue.
deQueue() - Used to delete a value from
the Circular Queue. This operation takes
place from the front of the Queue.
28
Representation of Circular Queue using Arrays and a Linked List
Here we can implement the circular queue using both the 1-D array and the Linked list.
However, implementing a circular link is a new addition that we need to execute. Additionally, this
queue works by the process of circular incrementation. That is, when you reach the end of a
queue, you start from the beginning of a queue. The circular incrementation is achievable with the
help of the modulo division.(%)
Here, the MaxSize of queue is 5, and the rear
pointer has already reached the end of a queue.
There is one empty space at the beginning of a
queue, which means that the front pointer is
pointing to location 1.
29
Enqueue Algorithm
The following steps should be taken to enqueue(insert)data
into a queue
30
void Enqueue()
{
int item;
if ((rear + 1) % max == front)
{
printf("Overflow Error\n");
}
else
{
if (front == -1)
front = 0;
rear = (rear + 1) % max;
printf("Enter the element for Insertion: ");
scanf("%d", &item);
Q[rear] = item;
}
}
31
void Dequeue() void display() {
{ int i;
int item; if (front == -1) {
if (front == -1)
printf("Queue is empty\n");
{
printf("Underflow\n");
} else {
return; printf("Queue elements are:\
} n");
else i = front;
{ while (i != rear) {
item = Q[front]; printf("%d\n", Q[i]);
printf("\n Deleted item=%d\n", item); i = (i + 1) % max;
if (front == rear) }
front = rear = -1;
printf("%d\n", Q[rear]);
else
front = (front + 1) % max;
}
} }
}
32
Priority Queue
A priority queue is another special type of Queue data structure in which each element has some priority
associated with it .Based on the priority, the elements are arranged in a priority queue. If the elements occur
with same priority, then they are served according to the FIFO principle.
In priority Queue, the insertion takes place based on the arrival while the deletion occurs based on
the priority queue can be shown as
33
The priority queue can be implemented in four ways that include Arrays, Linked list, Heap data structure
and binary search tree .
The heap data structure is the most efficient way of implementing the priority queue , so we
will implement the priority queue using a heap data structure . Now ,first we understand the reason why
heap is the most efficient way among all the other data structures
34
What is heap?
A heap is a tree based data structure with the following properties:
1. It is a complete binary tree that is ,each level of the tree is completely filles ,expect possibly
the bottom level. At this level, it is filled from left to right.
2. It satisfies the heap-order property: The data item stored in each node is greater than or equal
to the data items stored in its children
Complete Incomplete
35
Types of Heap
Min heap: The value of the parent node Max Heap: The value of the parent node is
should be less than or equal to either of its greater than or equal to its children.
children.
36
37
Applications of Priority Queue:
39
2. Output restricted Queue: In output restricted queue, deletion operation can be performed at only
one end, while insertion can be performed from both ends.
Operations on Deque:
1. Insertion at front
2. Deletion from front
3. Insertion at rear
4. Deletion from rear
5. isFull( )
6. isEmpty( )
40
void insert_at_Front(int value)
{
if ((Front == 0 && Rear == SIZE - 1) || (Front == (Rear + 1) % SIZE))
{
Printf(“Overflow”); return
} deque = [-1, -1, -1, -1, -1] (all elements are -1)
if(Front==-1 && Rear==-1)
{
Front = Rear = 0;
deque = [10, -1, -1, -1, -1]
deque[Front] = value;
}
else if(Front == 0)
{
Front = SIZE-1; deque = [10, -1, -1, -1, 20]
deque[Front] = value;
}
else
{
Front = (Front - 1 + SIZE) % SIZE; deque = [10, -1, -1, 30, 20]
deque[Front]= value;
}
}
41
void delete_at_Front()
{
if(Front==-1 && Rear==-1) deque = [10, 20, 30, 40, 50]
{
printf("Underflow");
return;
}
else if(Front == Rear)
{
printf( “%d\n”, deque[Front]);
Front=-1;
Rear=-1;
}
else if(Front == SIZE-1)
{
printf(“%d\n”, deque[Front]);
Front = 0;
}
else
{
printf(“%d\n”, deque[Front]);
Front = Front+1;
42
}
void inseret_at_Rear(int value)
{
if ((Front == 0 && Rear == SIZE - 1) || (Front == Rear + 1))
{
Printf(“Overflow”); return;
}
if(Front==-1 && rear==-1) deque = [-1, -1, -1, -1, -1] (all elements are -1)
{
Front=Rear=0; deque = [10, -1, -1, -1, -1]
deque[Rear] = value;
}
else if(Rear == SIZE-1)
{
Rear = 0;
deque[Rear] = value;
}
else deque = [10, 20, -1, -1, -1]
{
Rear++; deque = [10, 20, 30, 40, 50]
deque[Rear] = value;
}
}
43
void delete_at_Rear() else
{ { deque = [10, 20, 30, 40,
if(Front==-1 && Rear==-1) printf(deque[Rear]); 50]
{ Rear = Rear-1; f=0 , r=4
printf("Underflow"); }
return; }
}
else if(Front == Rear)
{
printf(deque[Rear]);
Front = -1;
Rear = -1;
}
else if(Rear == 0)
{
printf(deque[Rear]);
Rear = SIZE-1;
}
44
“A small aim is a
crime.”
Dr. APJ Abdul
Kalam
Thank you
45