FDS Answer Bank 11-20
FDS Answer Bank 11-20
A Double Ended Queue (Deque) is a data structure that allows insertion and deletion of elements
from both ends (front and rear). Here, we’ll implement a deque using a circular array.
Basic Operations
Insert at Front
Insert at Rear
Check if Empty
Check if Full
Initialization
function initializeDeque(size):
front = -1
rear = 0
capacity = size
Insert at Front
function insertFront(value):
if (isFull()):
print("Overflow")
return
front = 0
rear = 0
front = capacity - 1
else:
front = front - 1
deque[front] = value
Insert at Rear
function insertRear(value):
if (isFull()):
print("Overflow")
return
front = 0
rear = 0
rear = 0
else:
rear = rear + 1
deque[rear] = value
function deleteFront():
if (isEmpty()):
print("Underflow")
return
front = -1
rear = -1
front = 0
else:
front = front + 1
function deleteRear():
if (isEmpty()):
print("Underflow")
return
front = -1
rear = -1
rear = capacity - 1
else:
rear = rear - 1
Check if Empty
function isEmpty():
Check if Full
function isFull():
Python
class Deque:
self.front = -1
self.rear = 0
self.size = size
def isFull(self):
def isEmpty(self):
return self.front == -1
if self.isFull():
print("Overflow")
return
self.front = 0
self.rear = 0
elif self.front == 0:
self.front = self.size - 1
else:
self.front -= 1
self.deque[self.front] = value
if self.isFull():
print("Overflow")
return
self.front = 0
self.rear = 0
self.rear = 0
else:
self.rear += 1
self.deque[self.rear] = value
def deleteFront(self):
if self.isEmpty():
print("Underflow")
return
self.front = -1
self.rear = -1
self.front = 0
else:
self.front += 1
def deleteRear(self):
if self.isEmpty():
print("Underflow")
return
self.front = -1
self.rear = -1
elif self.rear == 0:
self.rear = self.size - 1
else:
self.rear -= 1
# Example usage:
dq = Deque(5)
dq.insertRear(10)
dq.insertFront(20)
dq.insertRear(30)
dq.deleteFront()
dq.deleteRear()
Quick Sort is a highly efficient sorting algorithm based on the divide-and-conquer principle. It works
by selecting a ‘pivot’ element from the array and partitioning the other elements into two sub-
arrays, according to whether they are less than or greater than the pivot. The sub-arrays are then
sorted recursively.
pivot = arr[high]
i = low - 1
i=i+1
return i + 1
Example: Sorting the Array {4, 7, 11, 3, 4, 66, 78, 83, 12}
Let’s go through the steps of sorting this array using Quick Sort:
Pass 1:
• Pivot: 12
• Pivot Index: 5
Recursive Calls:
• quickSort(arr, 0, 4)
• quickSort(arr, 6, 8)
Pass 2 (Left Sub-array):
• Pivot: 4
• Pivot Index: 1
Recursive Calls:
• quickSort(arr, 2, 4)
• Pivot: 4
• Pivot Index: 2
Recursive Calls:
• quickSort(arr, 3, 4)
• Pivot: 11
• Pivot Index: 4
Recursive Calls:
• Pivot: 66
• Pivot Index: 6
Recursive Calls:
• quickSort(arr, 7, 8)
• Pivot: 78
Recursive Calls:
• Time Complexity:
o Worst Case: (O(n^2)) (occurs when the smallest or largest element is always chosen
as the pivot)
Quick Sort is generally faster in practice compared to other (O(n \log n)) algorithms like Merge Sort
and Heap Sort, especially for large datasets. However, its performance can degrade to (O(n^2)) if the
pivot selection is poor.
To convert a prefix expression to an infix expression using a stack, follow these steps:
If the character is an operator, pop two operands from the stack, combine them into a new string
with the operator in between, and push this new string back onto the stack.
Example Conversion
Step-by-Step Conversion:
Initial Stack: []
Stack: [‘e’]
Read ‘d’: Push to stack.
Read ‘-’: Pop ‘d’ and ‘e’, combine to form ‘(d - e)’, push back.
Read ‘/’: Pop ‘b’ and ‘c’, combine to form ‘(b / c)’, push back.
Read ‘+’: Pop ‘a’ and ‘(b / c)’, combine to form ‘(a + (b / c))’, push back.
Final Step: Combine the remaining elements in the stack with the operator ‘-’.
The infix expression for the given prefix expression +a/bc-de is:
This step-by-step process ensures that the operators are correctly placed between their operands,
respecting the order of operations.
A stack is a linear data structure that follows the Last In, First Out (LIFO) principle. Here are some
common applications of stacks with examples:
o Example: When a function calls another function, the current function’s state (local
variables, return address) is pushed onto the stack. When the called function
completes, the state is popped from the stack to resume execution.
o Use Case: Compilers use stacks to evaluate expressions and generate machine code.
3. Backtracking:
o Example: Solving maze problems where you need to backtrack to the previous
position if a dead end is reached.
o Example: Each action (typing, deleting) is pushed onto a stack. To undo an action,
the last action is popped from the stack and reversed.
5. Parenthesis Checking:
6. Memory Management:
Recursion is a technique where a function calls itself to solve a problem. It breaks down a problem
into smaller subproblems of the same type.
Types of Recursion
1. Direct Recursion:
o Code:
o void directRecursion(int n) {
o if (n > 0) {
o directRecursion(n - 1);
o }
o }
2. Indirect Recursion:
o Example: A function calls another function, which in turn calls the first function.
o Code:
o void functionB(int n) {
o if (n > 0) {
o functionA(n - 1);
o }
o }
o void functionA(int n) {
o if (n > 0) {
o functionB(n - 1);
o }
o }
3. Tail Recursion:
o Code:
o void tailRecursion(int n) {
o if (n > 0) {
o tailRecursion(n - 1);
o }
o }
4. Non-Tail Recursion:
o Example: The recursive call is not the last operation in the function.
o Code:
o int nonTailRecursion(int n) {
o if (n == 0) return 1;
o }
5. Linear Recursion:
o Example: Each function call makes a single recursive call.
o Code:
o int linearRecursion(int n) {
o if (n == 0) return 0;
o }
6. Tree Recursion:
o Code:
o int fibonacci(int n) {
o if (n <= 1) return n;
o }
Example of Recursion
Factorial Calculation:
int factorial(int n) {
if (n == 0) return 1;
Explanation:
Recursion is a powerful tool for solving problems that can be broken down into smaller, similar
subproblems. Understanding its variants helps in choosing the right approach for different scenarios.
A Double Ended Queue (Deque) is a data structure that allows insertion and deletion of elements
from both ends (front and rear). Here’s how you can implement a deque using an array in C++ and
perform the operations to create and display the deque.
Initialization
function initializeDeque(size):
rear = 0
capacity = size
Insert at Front
function insertFront(value):
if (isFull()):
print("Overflow")
return
front = 0
rear = 0
front = capacity - 1
else:
front = front - 1
deque[front] = value
Insert at Rear
function insertRear(value):
if (isFull()):
print("Overflow")
return
front = 0
rear = 0
rear = 0
else:
rear = rear + 1
deque[rear] = value
function deleteFront():
if (isEmpty()):
print("Underflow")
return
front = -1
rear = -1
front = 0
else:
front = front + 1
function deleteRear():
if (isEmpty()):
print("Underflow")
return
front = -1
rear = -1
rear = capacity - 1
else:
rear = rear - 1
Check if Empty
function isEmpty():
Check if Full
function isFull():
Display Deque
function displayDeque():
if (isEmpty()):
print("Deque is empty")
return
index = front
print(deque[index])
print(deque[rear])
#include <iostream>
class Deque {
private:
int* deque;
int front;
int rear;
int size;
public:
Deque(int size) {
this->size = size;
front = -1;
rear = 0;
bool isFull() {
}
bool isEmpty() {
if (isFull()) {
return;
if (front == -1) {
front = 0;
rear = 0;
} else if (front == 0) {
front = size - 1;
} else {
front = front - 1;
deque[front] = value;
if (isFull()) {
return;
if (front == -1) {
front = 0;
rear = 0;
rear = 0;
} else {
rear = rear + 1;
deque[rear] = value;
void deleteFront() {
if (isEmpty()) {
return;
if (front == rear) {
front = -1;
rear = -1;
front = 0;
} else {
front = front + 1;
void deleteRear() {
if (isEmpty()) {
return;
if (front == rear) {
front = -1;
rear = -1;
} else if (rear == 0) {
rear = size - 1;
} else {
rear = rear - 1;
void displayDeque() {
if (isEmpty()) {
return;
};
int main() {
Deque dq(5);
dq.insertRear(10);
dq.insertFront(20);
dq.insertRear(30);
dq.displayDeque(); // Output: 20 10 30
dq.deleteFront();
dq.displayDeque(); // Output: 10 30
dq.deleteRear();
dq.displayDeque(); // Output: 10
return 0;
}
This code defines a Deque class with methods to insert and delete elements from both ends, and to
check if the deque is full or empty. The displayDeque method prints the elements in the deque.
The main function demonstrates basic operations on the deque.
A Queue is a linear data structure that follows the First-In-First-Out (FIFO) principle. This means that
the first element added to the queue will be the first one to be removed. It has two primary
operations:
Initialization
function initializeQueue(size):
front = -1
rear = -1
capacity = size
Enqueue
function enqueue(value):
if (isFull()):
print("Overflow")
return
front = 0
queue[rear] = value
Dequeue
function dequeue():
if (isEmpty()):
print("Underflow")
return
value = queue[front]
front = -1
rear = -1
else:
return value
IsEmpty
function isEmpty():
IsFull
function isFull():
Peek/Front
function peek():
if (isEmpty()):
print("Queue is empty")
return
return queue[front]
#include <iostream>
class Queue {
private:
int* queue;
int front;
int rear;
int size;
int capacity;
public:
Queue(int capacity) {
this->capacity = capacity;
front = -1;
rear = -1;
size = 0;
bool isFull() {
bool isEmpty() {
return size == 0;
if (isFull()) {
return;
if (front == -1) {
front = 0;
size++;
void dequeue() {
if (isEmpty()) {
return;
if (front == rear) {
front = -1;
rear = -1;
} else {
size--;
int peek() {
if (isEmpty()) {
return -1;
return queue[front];
void displayQueue() {
if (isEmpty()) {
return;
}
int i = front;
while (i != rear) {
i = (i + 1) % capacity;
};
int main() {
Queue q(5);
q.enqueue(10);
q.enqueue(20);
q.enqueue(30);
q.displayQueue(); // Output: 10 20 30
q.dequeue();
q.displayQueue(); // Output: 20 30
cout << "Front element: " << q.peek() << endl; // Output: 20
return 0;
This code defines a Queue class with methods to enqueue, dequeue, check if the queue is empty or
full, peek at the front element, and display the queue. The main function demonstrates basic
operations on the queue.
A Circular Queue is a linear data structure that follows the First-In-First-Out (FIFO) principle but
connects the last position back to the first position to make a circle. This helps in efficiently utilizing
the space by reusing the empty slots created by dequeuing elements.
Initialization
function initializeQueue(size):
front = -1
rear = -1
capacity = size
Enqueue
function enqueue(value):
if (isFull()):
print("Overflow")
return
front = 0
queue[rear] = value
Dequeue
function dequeue():
if (isEmpty()):
print("Underflow")
return
value = queue[front]
front = -1
rear = -1
else:
return value
IsEmpty
function isEmpty():
return (front == -1)
IsFull
function isFull():
Peek/Front
function peek():
if (isEmpty()):
print("Queue is empty")
return
return queue[front]
#include <iostream>
class CircularQueue {
private:
int* queue;
int front;
int rear;
int size;
int capacity;
public:
CircularQueue(int capacity) {
this->capacity = capacity;
front = -1;
rear = -1;
size = 0;
}
bool isFull() {
bool isEmpty() {
if (isFull()) {
return;
if (front == -1) {
front = 0;
queue[rear] = value;
size++;
void dequeue() {
if (isEmpty()) {
return;
if (front == rear) {
front = -1;
rear = -1;
} else {
front = (front + 1) % capacity;
size--;
int peek() {
if (isEmpty()) {
return -1;
return queue[front];
void displayQueue() {
if (isEmpty()) {
return;
int i = front;
while (i != rear) {
i = (i + 1) % capacity;
};
int main() {
CircularQueue cq(5);
cq.enqueue(10);
cq.enqueue(20);
cq.enqueue(30);
cq.displayQueue(); // Output: 10 20 30
cq.dequeue();
cq.displayQueue(); // Output: 20 30
cout << "Front element: " << cq.peek() << endl; // Output: 20
return 0;
This code defines a CircularQueue class with methods to enqueue, dequeue, check if the queue is
empty or full, peek at the front element, and display the queue. The main function demonstrates
basic operations on the circular queue.
A Priority Queue is a special type of queue in which each element is associated with a priority.
Elements are served based on their priority rather than their order in the queue. The element with
the highest priority is served before the elements with lower priority.
o In a Min Priority Queue, the element with the smallest priority value is given the
highest priority.
o Example: Consider a hospital emergency room where patients with the most critical
conditions are treated first. Here, the severity of the condition is the priority, and
lower values (more critical) are served first.
o In a Max Priority Queue, the element with the highest priority value is given the
highest priority.
o Example: Consider a task scheduling system where tasks with the highest
importance are executed first. Here, higher priority values (more important tasks)
are served first.
Let’s consider a Min Priority Queue with the following elements and their priorities:
Table
Element Priority
Task A 3
Element Priority
Task B 1
Task C 2
o After inserting Task A, Task B, and Task C, the queue looks like this: [Task B, Task C,
Task A] (sorted by priority).
• Dequeue: Remove the element with the highest priority (smallest value).
o Dequeue operation will remove Task B first, followed by Task C, and then Task A.
Let’s consider a Max Priority Queue with the following elements and their priorities:
Table
Element Priority
Task X 5
Task Y 9
Task Z 7
o After inserting Task X, Task Y, and Task Z, the queue looks like this: [Task Y, Task Z,
Task X] (sorted by priority).
• Dequeue: Remove the element with the highest priority (largest value).
o Dequeue operation will remove Task Y first, followed by Task Z, and then Task X.
Priority queues can be implemented using various data structures such as arrays, linked lists, heaps,
or binary search trees. The most efficient implementation is typically done using a heap.
class MinHeap:
function insert(value):
heapifyUp()
function heapifyUp():
function removeMin():
if heap is empty:
return "Underflow"
min = heap[0]
heapifyDown()
return min
function heapifyDown():
index = 0
break
else:
index = smallerChildIndex
This pseudocode outlines the basic operations for a Min-Heap, which can be used to implement a
Min Priority Queue. The insert function adds a new element while maintaining the heap property,
and the removeMin function removes the element with the highest priority (smallest value).
When a queue is implemented using a linked list, it consists of nodes where each node contains two
parts:
Basic Operations
4. IsFull: Checks if the queue is full (not typically applicable for linked list implementation
unless memory is exhausted).
A queue is considered empty when there are no elements in it. For a linked list implementation, this
condition is met when the front pointer is NULL.
function isEmpty():
In a linked list implementation, the queue is generally not considered full unless the system runs out
of memory to allocate new nodes. However, if we impose a size limit, the queue can be considered
full when the number of elements reaches this limit.
function isFull():
if (node == NULL):
return true
else:
delete node
return false
#include <iostream>
class Node {
public:
int data;
Node* next;
};
class Queue {
private:
Node* front;
Node* rear;
public:
Queue() {
front = NULL;
rear = NULL;
bool isEmpty() {
bool isFull() {
return true;
} else {
delete temp;
return false;
if (temp == NULL) {
return;
temp->data = value;
temp->next = NULL;
if (front == NULL) {
} else {
rear->next = temp;
rear = temp;
void dequeue() {
if (isEmpty()) {
return;
front = front->next;
if (front == NULL) {
rear = NULL;
delete temp;
void displayQueue() {
if (isEmpty()) {
return;
temp = temp->next;
};
int main() {
Queue q;
q.enqueue(10);
q.enqueue(20);
q.enqueue(30);
q.displayQueue(); // Output: 10 20 30
q.dequeue();
q.displayQueue(); // Output: 20 30
return 0;
}
This code defines a Queue class with methods to enqueue, dequeue, check if the queue is empty or
full, and display the queue. The main function demonstrates basic operations on the queue.
Queues are widely used in various fields due to their ability to manage data in a First-In-First-Out
(FIFO) manner. Here are some common applications of queues, each elaborated with a suitable
example:
CPU Scheduling:
Example: In operating systems, processes are scheduled using queues. The ready queue holds all
processes that are ready to execute and waiting for CPU time. The CPU scheduler selects the process
at the front of the queue for execution.
Explanation: This ensures that processes are executed in the order they arrive, providing fair CPU
time to all processes.
Printer Spooling:
Example: When multiple print jobs are sent to a printer, they are stored in a queue. The printer
processes each job in the order it was received.
Explanation: This prevents conflicts and ensures that print jobs are handled sequentially, avoiding
any job being skipped or delayed unnecessarily.
Example: Web servers use queues to manage incoming HTTP requests. Each request is queued and
processed in the order it arrives.
Explanation: This helps in managing high traffic efficiently, ensuring that each request is handled in a
timely manner without overloading the server.
Example: In call centers, incoming calls are placed in a queue. Calls are answered in the order they
are received.
Explanation: This ensures that customers are served on a first-come, first-served basis, improving
customer satisfaction and service efficiency.
Example: BFS algorithm uses a queue to explore nodes level by level. Starting from a source node, it
visits all its neighbors before moving to the next level.
Explanation: This is useful in finding the shortest path in unweighted graphs and in scenarios like
social network analysis, where connections are explored level by level.
Task Scheduling:
Example: In real-time systems, tasks are scheduled using queues. Tasks are added to the queue
based on their arrival time and priority.
Explanation: This ensures that tasks are executed in a timely manner, respecting their priority and
arrival order, which is crucial for maintaining system performance and reliability.
Example: Routers use queues to manage network packets. Incoming packets are queued and
processed in the order they arrive.
Explanation: This helps in managing network traffic efficiently, ensuring that packets are transmitted
without loss or delay.
Simulation Systems:
Example: In simulation systems, events are managed using queues. Events are queued and processed
in the order they are scheduled to occur.
Explanation: This allows for accurate simulation of real-world processes, such as traffic flow,
manufacturing processes, and customer service systems.
#include <iostream>
class Node {
public:
int data;
Node* next;
};
class Queue {
private:
Node* front;
Node* rear;
public:
Queue() {
front = NULL;
rear = NULL;
}
bool isEmpty() {
temp->data = value;
temp->next = NULL;
if (rear == NULL) {
} else {
rear->next = temp;
rear = temp;
void dequeue() {
if (isEmpty()) {
return;
front = front->next;
if (front == NULL) {
rear = NULL;
delete temp;
}
void displayQueue() {
if (isEmpty()) {
return;
temp = temp->next;
};
int main() {
Queue q;
q.enqueue(10);
q.enqueue(20);
q.enqueue(30);
q.displayQueue(); // Output: 10 20 30
q.dequeue();
q.displayQueue(); // Output: 20 30
return 0;
This code demonstrates a basic queue implementation using a linked list, which can be used in
various applications as described above.