Iteration vs Recursion Explained
Iteration vs Recursion Explained
1. Iteration
Definition: Iteration means repeatedly executing a set of instructions until a condition is
met.
Implemented using loops (for, while, do-while).
Flow: Control goes back to the loop condition after each execution.
Memory: Uses a single memory block (no function call overhead).
┌───────────┐
│ Initialize │
└─────┬─────┘
│
┌─────▼─────┐
│ Condition │◄───────────┐
└─────┬─────┘ │
│True │
┌─────▼─────┐ │
│ Statements│ │
└─────┬─────┘ │
│ │
└──────────────────┘
│False
▼
Exit Loop
2. Recursion
Definition: Recursion is when a function calls itself directly or indirectly to solve a
problem.
Each recursive call creates a new activation record on the call stack.
Best suited for problems that can be divided into smaller sub-problems.
3. Principle of Recursion
1. Base Case: Stops recursion (prevents infinite loop).
Example: if (n == 0) return 1;
2. Recursive Case: Function calls itself with smaller input.
Example: return n * fact(n-1);
3. Progress Towards Base Case: Input size must decrease to reach termination.
4. Types of Recursion
a) Head Recursion
b) Tail Recursion
Diagram Difference:
Example: Factorial
Recursive:
int fact(int n) {
if (n==0) return 1;
return n * fact(n-1);
}
Iterative:
int fact(int n) {
int result = 1;
for(int i=1; i<=n; i++) result *= i;
return result;
}
Recursive:
Iterative:
B) Fibonacci Series
Recursive:
int fib(int n) {
if (n<=1) return n;
return fib(n-1)+fib(n-2);
}
Iterative:
void fibIter(int n) {
int a=0, b=1, c;
for(int i=0; i<n; i++) {
printf("%d ", a);
c = a+b;
a=b; b=c;
}
}
C) Tower of Hanoi
Recursive:
Explanation:
o Move n-1 disks from source → auxiliary.
o Move nth disk from source → destination.
o Move n-1 disks from auxiliary → destination.
[[{{(())}}]]
[][][](){}
([)]
((()]))
[{()]
Program for parentheses check and balance
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
if (top == MAX_SIZE - 1) {
printf("Overflow stack!\n");
return;
}
top++;
stack[top] = data;
}
// Function to pop a character from the stack
char pop() {
if (top == -1) {
printf("Empty stack!\n");
return ' ';
top--;
return data;
return 1;
return 1;
} else if (char1 == '{' && char2 == '}') {
return 1;
} else {
return 0;
}
}
if (top == -1) {
} else {
// Main function
int main() {
char text[MAX_SIZE];
if (isBalanced(text)) {
printf("The expression is balanced.\n");
} else {
return 0; }
[ DATA STRUCTURES]
Chapter - 05 : “Queues
Queues”
QUEUES
10 20 30 40 50 60 70 80
Front Rear
In fig (1), 10 is the first element and 80 is the last element added to the
Queue. Similarly, 10 would be the first element to get removed and 80 would be the last element
to get removed.
0 1 2 3 4 5 6
F R
Fig. 2(a) Empty Queue
F = 0 and R = 0
20
F R
Fig. 2(b) One Element Queue
F = 0 and R = 1
20 30
F R
Fig. 2(c) Two Element Queue
F = 0 and R = 2
20 30 40
F R
Fig. 2(d) Three Element Queue
It is clear from the above figures that whenever we insert an element in the queue,
the value of Rear is incremented by one i.e.
Rear = Rear + 1
Also, during the insertion of the first element in the queue we always incremented
the Front by one i.e.
Front = Front + 1
Afterwards the Front will not be changed during the entire operation. The following
figures show Queue graphically during deletion operation :
F = 1 and R = 2
30 40
F R
Fig. 2(e) One Element (20) Deleted from Front
F = 2 and R = 2
40
F R
Fig. 2(f) Second Element (30) Deleted from Front
This is clear from Fig. 2(e) and 2(f), that whenever an element is removed from the queue,
the value of Front is incremented by one i.e.,
Front = Front + 1
Now, if we insert any element in the queue, the queue will look like :
F = 2 and R = 3
40 50
F R
Fig. 2(g) Insertion after Deletion
Static implementation :
Static implementation of Queue is represented by arrays. If Queue is implemented
using arrays, we must be sure about the exact number of elements we want to store in the
queue, because we have to declare the size of the array at design time or before the
processing starts. In this case, the beginning of the array will become the front for the
queue and the last location of the array will act as rear for the queue. Fig. (3) shows the
representation of a queue as an array.
Front Rear
Fig. (3) Representation of a Queue as an array
The following relation gives the total number of elements present in the queue,
when implemented using arrays :
rear – front + 1
Also note that if front > rear, then there will be no element in the queue or queue is
empty.
OPERATIONS ON A QUEUE
The basic operations that can be performed on queue are :
Let QUEUE[MAXSIZE] is an array for implementing the Linear Queue & NUM is the
element to be inserted in linear queue, FRONT represents the index number of the element at the
beginning of the queue and REAR represents the index number of the element at the end of the
Queue.
void lqinsert()
{
int num;
if(rear==MAXSIZE-1)
{
printf("\nQueue is full (Queue overflow)");
return;
}
printf("\nEnter the element to be inserted : ");
scanf("%d",&num);
rear++;
queue[rear]=num;
if(front==-1)
front=0;
}
Let QUEUE[MAXSIZE] is an array for implementing the Linear Queue & NUM is the
element to be deleted from linear queue, FRONT represents the index number of the element at
the beginning of the queue and REAR represents the index number of the element at the end of
the Queue.
void lqdelete()
{
if(front == -1)
{
printf("\nQueue is empty (Queue underflow)");
return;
}
int num;
num=queue[front];
printf("\nDeleted element is : %d",num);
front++;
if(front>rear)
front=rear=-1;
}
Program 1 : Static implementation of Linear Queues using arrays
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#define MAXSIZE 5
void initialize();
void lqinsert();
void lqdelete();
void lqtraverse();
int queue[MAXSIZE];
int front,rear;
void main()
{
clrscr();
initialize();
int choice;
while(1)
{
clrscr();
printf("\nSTATIC IMPLEMENTATION OF LINEAR QUEUE");
printf("\n-------------------------------------");
printf("\n1. Insert");
printf("\n2. Delete");
printf("\n3. Traverse");
printf("\n4. Exit");
printf("\n-------------------------------------");
printf("\n\nEnter your choice [1/2/3/4] : ");
scanf("%d",&choice);
switch(choice)
{
case 1 : lqinsert();
break;
case 2 : lqdelete();
break;
case 3 : lqtraverse();
break;
case 4 : exit(0);
default : printf("\nInvalid choice");
}
getch();
}
}
// Function to initialize queue
void initialize()
{
front=rear=-1;
}
void lqinsert()
{
int num;
if(rear==MAXSIZE-1)
{
printf("\nQueue is full (Queue overflow)");
return;
}
printf("\nEnter the element to be inserted : ");
scanf("%d",&num);
rear++;
queue[rear]=num;
if(front==-1)
front=0;
}
void lqdelete()
{
if(front==-1)
{
printf("\nQueue is empty (Queue underflow)");
return;
}
int num;
num=queue[front];
printf("\nDeleted element is : %d",num);
front++;
if(front>rear)
front=rear=-1;
}
1. // Function to display Queue
void lqtraverse()
{
if(front==-1)
{
printf("\nQueue is empty (Queue underflow)");
return;
}
else
{
printf("\nQueue elements are : \n");
for(int i=front;i<=rear;i++)
printf("%d\t",queue[i]);
}
}
struct queue
{
int info;
struct queue *link;
}*start=NULL;
ALGORITHMS FOR INSERTION & DELETION IN A LINEAR QUEUE FOR DYNAMIC
IMPLEMENTATION USING LINKED LIST
void lqinsert()
{
struct queue *ptr;
int num;
ptr=(struct queue*)malloc(sizeof(struct queue));
printf("\nEnter element to be inserted in queue : ");
scanf("%d",&num);
ptr->info=num;
ptr->link=NULL;
if(front==NULL)
{
front=ptr;
rear=ptr;
}
else
{
rear->link=ptr;
rear=ptr;
}
}
(2) Algorithm for Deleting a node from a Linear Queue :
Let PTR is the structure pointer which deallocates memory of the first node in the
linear queue & NUM is the element to be deleted from queue, INFO represents the
information part of the deleted node and LINK represents the link or next pointer of the
deleted node pointing to the address of next node. FRONT represents the address of first
node, REAR represents the address of the last node.
Step 1 : If FRONT = NULL : then
Write ‘Queue is Empty(Queue Underflow)’ and return.
[End of If structure]
Step 2 : Set PTR = FRONT
Step 3 : Set NUM = PTR->INFO
Step 4 : Write ‘Deleted element from linear queue is : ‘,NUM.
Step 5 : Set FRONT = FRONT->LINK
Step 6 : If FRONT = NULL : then
Set REAR = NULL.
[End of If Structure].
Step 7 : Deallocate memory of the node at the beginning of queue using PTR.
Step 8 : Exit.
void lqdelete()
{
if(front==NULL)
{
printf("\nQueue is empty (Queue underflow)");
return;
}
struct queue *ptr;
int num;
ptr=front;
num=ptr->info;
printf("\nThe deleted element is : %d",num);;
front=front->link;
if(front==NULL)
rear=NULL;
free(ptr);
}
}
Program 2 : Dynamic implementation of linear queue using pointers
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
struct queue
{
int info;
struct queue *link;
}*front,*rear;
void initialize();
void lqinsert();
void lqdelete();
void lqtraverse();
void main()
{
int choice;
initialize();
while(1)
{
clrscr();
printf("\nDYNAMIC IMPLEMENTATION OF LINEAR QUEUE");
printf("\n1. Insert");
printf("\n2. Delete");
printf("\n3. Traverse");
printf("\n4. Exit");
printf("\n\nEnter your choice [1/2/3/4] : ");
scanf("%d",&choice);
switch(choice)
{
case 1: lqinsert();
break;
case 2: lqdelete();
break;
case 3: lqtraverse();
break;
case 4: exit(0);;
default : printf("\nInvalid choice");
}
getch();
}
}
// Function for initialize linear Queue
void initialize()
{
front=rear=NULL;
}
void lqinsert()
{
struct queue *ptr;
int num;
ptr=(struct queue*)malloc(sizeof(struct queue));
printf("\nEnter element to be inserted in queue : ");
scanf("%d",&num);
ptr->info=num;
ptr->link=NULL;
if(front==NULL)
{
front=ptr;
rear=ptr;
}
else
{
rear->link=ptr;
rear=ptr;
}
}
void lqdelete()
{
if(front==NULL)
{
printf("\nQueue is empty (Queue underflow)");
return;
}
struct queue *ptr;
int num;
ptr=front;
num=ptr->info;
printf("\nThe deleted element is : %d",num);;
front=front->link;
if(front==NULL)
rear=NULL;
free(ptr);
}
CIRCULAR QUEUES
The queue that we implemented using an array suffers from one limitation. In that
implementation there is a possibility that the queue is reported as full (since rear has
reached the end of the array), even though in actuality there might be empty slots at the
beginning of the queue. To overcome this limitation we can implement the queue as a
circular queue. Here as we go on adding elements to the queue and reach the end of the
array, the next element is stored in the first slot the array (provided it is free). Suppose an
array arr of n elements is used to implement a circular queue we may reach arr[n-1]. We
cannot add any more elements to the queue since we have reached at the end of the
array. Instead of reporting the queue as full, if some elements in the queue have been
deleted then there might be empty slots at the beginning of the queue. In such a case
these slots would be filled by new elements being added to the queue. In short just
because we have reached the end of the array, the queue would not be reported as full.
The queue would be reported as full only when all the slots in the array stand occupied.
Figure (4) shows the pictorial representation of a circular queue.
Rear
Q[0]
50 Front
Q[4] 10 Q[1]
40
30 20
Q[3] Q[2]
Let CQUEUE[MAXSIZE] is an array for implementing the Circular Queue, where MAXSIZE
represents the max. size of array. NUM is the element to be inserted in circular queue, FRONT
represents the index number of the element at the beginning of the queue and REAR represents
the index number of the element at the end of the Queue.
void cqinsert()
{
int num;
if(front==(rear+1)%MAXSIZE)
{
printf("\nQueue is Full(Queue overflow)");
return;
}
printf("\nEnter the element to be inserted in circular queue : ");
scanf("%d",&num);
if(front==-1)
front=rear=0;
else
rear=(rear+1) % MAXSIZE;
cqueue[rear]=num;
}
if(front==rear)
front=rear=-1;
else
front=(front+1)%MAXSIZE;
}
int cqueue[MAXSIZE];
int front=-1,rear=-1;
void main()
{
int choice;
while(1)
{
clrscr();
printf("\nSTATIC IMPLEMENTATION OF CIRCULAR QUEUE");
printf("\n-------------------------------------");
printf("\n1. Insert");
printf("\n2. Delete");
printf("\n3. Traverse");
printf("\n4. Exit");
printf("\n-------------------------------------");
printf("\n\nEnter your choice [1/2/3/4] : ");
scanf("%d",&choice);
switch(choice)
{
case 1 : cqinsert();
break;
case 2 : cqdelete();
break;
case 3 : cqdisplay();
break;
case 4 : exit(0);
default : printf("\nInvalid choice");
}
getch();
}
}
if(front==rear)
front=rear=-1;
else
front=(front+1)%MAXSIZE;
}
In a linear queue with max. size 5, after inserting element at the last location (4) of
array, the elements can’t be inserted, because in a queue the new elements are always
inserted from the rear end, and rear here indicates to last location of the array (location
with subscript 4) even if the starting locations before front are free. But in a circular queue,
if there is element at the last location of queue, then we can insert a new element at the
beginning of the array.
PRIORITY QUEUE
A priority queue is a collection of elements where the elements are stored according to
their priority levels. The order in which the elements get added or removed is decided by the
priority of the element.
Following rules are applied to maintain a priority queue :
(1) The element with a higher priority is processed before any element of lower priority.
(2) If there are elements with the same priority, then the element added first in the queue
would get processed.
Priority queues are used for implementing job scheduling by the operating system where
jobs with higher priorities are to be processed first. Another application of Priority queues is
simulation systems where priority corresponds to event times.
There are mainly two ways of maintaining a priority queue in memory. One uses a one-
way list, and the other uses multiple queues. The ease or difficultly in adding elements to or
deleting them from a priority queue clearly depends on the representation that one chooses.
Though the insertion and deletion in a deque can be performed on both ends, it does
not follow the FIFO rule. The representation of a deque is given as follows -
Types of deque
There are two types of deque -
In input restricted queue, insertion operation can be performed at only one end, while
deletion can be performed from both ends.
In output restricted queue, deletion operation can be performed at only one end, while
insertion can be performed from both ends.
o Insertion at front
o Insertion at rear
o Deletion at front
o Deletion at rear
We can also perform peek operations in the deque along with the operations listed
above. Through peek operation, we can get the deque's front and rear elements of the
deque. So, in addition to the above operations, following operations are also supported
in deque -
In this operation, the element is inserted from the front end of the queue. Before
implementing the operation, we first have to check whether the queue is full or not. If
the queue is not full, then the element can be inserted from the front end by using the
below conditions -
o If the queue is empty, both rear and front are initialized with 0. Now, both will
point to the first element.
o Otherwise, check the position of the front if the front is less than 1 (front < 1),
then reinitialize it by front = n - 1, i.e., the last index of the array.
In this operation, the element is inserted from the rear end of the queue. Before
implementing the operation, we first have to check again whether the queue is full or
not. If the queue is not full, then the element can be inserted from the rear end by using
the below conditions -
o If the queue is empty, both rear and front are initialized with 0. Now, both will
point to the first element.
o Otherwise, increment the rear by 1. If the rear is at last index (or size - 1), then
instead of increasing it by 1, we have to make it equal to 0.
In this operation, the element is deleted from the front end of the queue. Before
implementing the operation, we first have to check whether the queue is empty or not.
If the queue is empty, i.e., front = -1, it is the underflow condition, and we cannot
perform the deletion. If the queue is not full, then the element can be inserted from the
front end by using the below conditions -
If the deque has only one element, set rear = -1 and front = -1.
Else if front is at end (that means front = size - 1), set front = 0.
In this operation, the element is deleted from the rear end of the queue. Before
implementing the operation, we first have to check whether the queue is empty or not.
If the queue is empty, i.e., front = -1, it is the underflow condition, and we cannot
perform the deletion.
If the deque has only one element, set rear = -1 and front = -1.
This operation is performed to check whether the deque is empty or not. If front = -1, it
means that the deque is empty.
Check full
This operation is performed to check whether the deque is full or not. If front = rear + 1,
or front = 0 and rear = n - 1 it means that the deque is full.
The time complexity of all of the above operations of the deque is O(1), i.e., constant.
Applications of deque
o Deque can be used as both stack and queue, as it supports both operations.
o Deque can be used as a palindrome checker means that if we read the string
from both ends, the string would be the same.
Implementation of deque
Now, let's see the implementation of deque in C programming language.
1. #include <stdio.h>
2. #define size 5
3. int deque[size];
4. int f = -1, r = -1;
5. // insert_front function will insert the value from the front
6. void insert_front(int x)
7. {
8. if((f==0 && r==size-1) || (f==r+1))
9. {
10. printf("Overflow");
11. }
12. else if((f==-1) && (r==-1))
13. {
14. f=r=0;
15. deque[f]=x;
16. }
17. else if(f==0)
18. {
19. f=size-1;
20. deque[f]=x;
21. }
22. else
23. {
24. f=f-1;
25. deque[f]=x;
26. }
27. }
28.
29. // insert_rear function will insert the value from the rear
30. void insert_rear(int x)
31. {
32. if((f==0 && r==size-1) || (f==r+1))
33. {
34. printf("Overflow");
35. }
36. else if((f==-1) && (r==-1))
37. {
38. r=0;
39. deque[r]=x;
40. }
41. else if(r==size-1)
42. {
43. r=0;
44. deque[r]=x;
45. }
46. else
47. {
48. r++;
49. deque[r]=x;
50. }
51.
52. }
53.
54. // display function prints all the value of deque.
55. void display()
56. {
57. int i=f;
58. printf("\nElements in a deque are: ");
59.
60. while(i!=r)
61. {
62. printf("%d ",deque[i]);
63. i=(i+1)%size;
64. }
65. printf("%d",deque[r]);
66. }
67.
68. // getfront function retrieves the first value of the deque.
69. void getfront()
70. {
71. if((f==-1) && (r==-1))
72. {
73. printf("Deque is empty");
74. }
75. else
76. {
77. printf("\nThe value of the element at front is: %d", deque[f]);
78. }
79.
80. }
81.
82. // getrear function retrieves the last value of the deque.
83. void getrear()
84. {
85. if((f==-1) && (r==-1))
86. {
87. printf("Deque is empty");
88. }
89. else
90. {
91. printf("\nThe value of the element at rear is %d", deque[r]);
92. }
93.
94. }
95.
96. // delete_front() function deletes the element from the front
97. void delete_front()
98. {
99. if((f==-1) && (r==-1))
100. {
101. printf("Deque is empty");
102. }
103. else if(f==r)
104. {
105. printf("\nThe deleted element is %d", deque[f]);
106. f=-1;
107. r=-1;
108.
109. }
110. else if(f==(size-1))
111. {
112. printf("\nThe deleted element is %d", deque[f]);
113. f=0;
114. }
115. else
116. {
117. printf("\nThe deleted element is %d", deque[f]);
118. f=f+1;
119. }
120. }
121.
122. // delete_rear() function deletes the element from the rear
123. void delete_rear()
124. {
125. if((f==-1) && (r==-1))
126. {
127. printf("Deque is empty");
128. }
129. else if(f==r)
130. {
131. printf("\nThe deleted element is %d", deque[r]);
132. f=-1;
133. r=-1;
134.
135. }
136. else if(r==0)
137. {
138. printf("\nThe deleted element is %d", deque[r]);
139. r=size-1;
140. }
141. else
142. {
143. printf("\nThe deleted element is %d", deque[r]);
144. r=r-1;
145. }
146. }
147.
148. int main()
149. {
150. insert_front(20);
151. insert_front(10);
152. insert_rear(30);
153. insert_rear(50);
154. insert_rear(80);
155. display(); // Calling the display function to retrieve the values of deque
156. getfront(); // Retrieve the value at front-end
157. getrear(); // Retrieve the value at rear-end
158. delete_front();
159. delete_rear();
160. display(); // calling display function to retrieve values after deletion
161. return 0;
162. }