DSD Modal Exam Expected Question
DSD Modal Exam Expected Question
PART-A o Disadvantages:
1. Define data structure and how the data types are classified at the higher ▪ No random access
level. ▪ Higher memory usage due to pointers
o A data structure is a way of organizing and storing data so that it can 15. Define Singly Linked List.
be accessed and modified efficiently. At a higher level, data types are
classified into primitive (e.g., int, char, float) and non-primitive types, o A singly linked list is a data structure where each node contains data
which include arrays, lists, stacks, queues, trees, and graphs. and a pointer to the next node in the sequence.
2. Define English ruler function. 16. Mention the basic principle behind the quick sort.
o An English ruler function typically refers to a recursive function that o Quick sort uses a divide-and-conquer strategy to partition an array
simulates drawing ticks on an English ruler. It is a way to into two subarrays based on a pivot element and then recursively
demonstrate recursion and is often used to illustrate divide-and- sorts the subarrays.
conquer algorithms. 17. Enlist 4 internal sorting techniques.
3. Differentiate between linear and non-linear data structure. o Bubble sort
o Linear data structures store data in a sequential manner, such as o Insertion sort
arrays, linked lists, stacks, and queues. Non-linear data structures
o Merge sort
store data hierarchically or in a graph manner, such as trees and
graphs. o Quick sort
4. List the applications of stack? 18. What do you mean by heap?
o Applications of stacks include: o A heap is a specialized tree-based data structure that satisfies the
heap property, where the key of each node is greater than or equal
▪ Function call management (call stack in programming)
to (max heap) or less than or equal to (min heap) the keys of its
▪ Expression evaluation and syntax parsing children.
▪ Undo mechanisms in text editors 19. What are the 2 stages in which heap sort is conducted?
▪ Depth-first search in graph algorithms o Building a heap from the input data
5. Justify why binary search cannot be performed using linked list. o Repeatedly removing the maximum element from the heap and
o Binary search requires random access to elements, which is efficient reconstructing the heap until it is empty
in arrays (O(1) time complexity). In a linked list, accessing an 20. Mention the sort which iteratively passes through a list to exchange the
element at a specific index takes O(n) time, making binary search first element with any element less than and repeats with a new first
inefficient. element.
6. Which hash function maintains the record in order of hash field values? o Selection sort
o A perfect hash function maintains the records in the order of hash 21. Draw a minheap for the following numbers: 12, 42, 25, 63, 9. [N/D’11]
field values, but in practice, such functions are rare. Order-
preserving hash functions can be used in specific scenarios to o The minheap for the numbers 12, 42, 25, 63, 9:
maintain order.
Copy code
7. What is the advantage of using multiway search tree?
9
o Multiway search trees, such as B-trees, allow for efficient insertion,
/\
deletion, and search operations. They are well-suited for disk-based
storage systems because they reduce the number of disk accesses. 12 25
8. Give the balance factor of an AVL tree. 22.Define binary tree. Give the binary tree node structure. [N/D’12]
o The balance factor of a node in an AVL tree is the difference in o A binary tree is a tree data structure where each node has at most
height between its left and right subtrees. It can be -1, 0, or 1 for all two children, referred to as the left child and the right child. The
nodes in a balanced AVL tree. node structure can be defined as:
9. Define DAG and shortest path of a graph. python
o A Directed Acyclic Graph (DAG) is a graph with directed edges and Copy code
no cycles. The shortest path in a graph is the path between two class TreeNode:
vertices that has the smallest sum of edge weights.
def __init__(self, value):
10. Define complete graph and finite graph?
self.value = value
o A complete graph is a graph where there is a unique edge between
every pair of vertices. A finite graph is a graph with a finite number self.left = None
of vertices and edges. self.right = None
11. List the various operations performed on list. 23.How does the AVL tree differ from binary search tree? [N/D’12]
o Operations on lists include insertion, deletion, traversal, searching, o An AVL tree is a self-balancing binary search tree where the
and sorting. difference in heights of left and right subtrees cannot be more than
12. State the difference between array and linked list. one for all nodes. A binary search tree does not have this balancing
property.
o An array has a fixed size and allows random access to elements. A
linked list has a dynamic size and allows efficient insertions and 24.How do we calculate the balance factor for each node in an AVL tree?
deletions but does not support random access. o The balance factor is calculated as the height of the left subtree
13. Give the applications of linked list. minus the height of the right subtree for each node.
o Applications of linked lists include dynamic memory allocation, 25.What is an acyclic graph? How it differs from undirected acyclic graph?
implementation of stacks and queues, graph adjacency lists, and o An acyclic graph has no cycles. In a directed acyclic graph (DAG),
managing free memory in operating systems. edges have a direction, while in an undirected acyclic graph, edges
14. What are the advantages and disadvantages of linked list? do not have a direction and the graph is also called a tree.
o Advantages: 26What is meant by strongly connected and weakly connected in a graph?
[May’12]
▪ Dynamic size
o In a directed graph, strongly connected means there is a path
between every pair of vertices. Weakly connected means the graph
32. List out all Object-Oriented Programming (OOP) concepts and explain in
is connected if direction is ignored.
detail.
27.Name the different ways of representing a graph.
Object-Oriented Programming (OOP) Concepts:
o Adjacency matrix
1. Class:
o Adjacency list
• A blueprint for objects that defines a set of attributes and methods.
o Edge list
• Example:
o Incidence matrix
python
28.Define graph traversals or what are the 2 traversal strategies used in a
Copy code
graph?
class Car:
o Graph traversal involves visiting all the vertices in a graph. The two
main strategies are Breadth-First Search (BFS) and Depth-First def __init__(self, model, year):
Search (DFS). self.model = model
29.Name two algorithms to find the minimum spanning tree. self.year = year
o Kruskal's algorithm 2. Object:
o Prim's algorithm • An instance of a class.
30.Differentiate between BFS and DFS. • Example:
o BFS explores vertices level by level, using a queue. DFS explores as python
far as possible along each branch before backtracking, using a stack
or recursion. Copy code
car1 = Car("Toyota", 2020)
3. Inheritance:
• Allows a new class to inherit attributes and methods from an existing
class.
• Example:
python
Copy code
class ElectricCar(Car):
def __init__(self, model, year, battery_size):
super().__init__(model, year)
self.battery_size = battery_size
PART-B 4. Polymorphism:
31. Explain in short about Python classes and objects. • The ability to present the same interface for different underlying
data types.
Python Classes and Objects:
• Example:
Class:
python
• A class in Python is a blueprint for creating objects (a particular data
structure). Copy code
• It defines a set of attributes (variables) and methods (functions) that the class Dog:
created objects will have. def speak(self):
• A class encapsulates data for the object. return "Woof!"
Object:
• An object is an instance of a class. class Cat:
• When a class is defined, no memory is allocated until an object of that def speak(self):
class is instantiated.
return "Meow!"
Example:
python
def animal_sound(animal):
Copy code
print(animal.speak())
class Person:
def __init__(self, name, age):
animal_sound(Dog()) # Output: Woof!
self.name = name
animal_sound(Cat()) # Output: Meow!
self.age = age
5. Encapsulation:
• Bundling the data and methods that operate on the data within one
p1 = Person("John", 36) unit, like a class.
print(p1.name) # Output: John • It restricts access to some of the object's components.
print(p1.age) # Output: 36 • Example:
In the above example: python
• Person is a class with __init__ method which initializes name and age Copy code
attributes.
class EncapsulatedObject:
• p1 is an object of the Person class.
def __init__(self, value): Detailed Explanation:
self.__value = value # private variable • Shallow Copy:
• A shallow copy creates a new object, but instead of creating new
copies of nested objects, it inserts references to them.
def get_value(self):
• This means that changes to the nested objects in either the original
return self.__value
or the copy will reflect in both.
6. Abstraction:
• Shallow copies are faster to create because they do not involve the
• Hiding the complex implementation details and showing only the creation of new objects for nested structures.
necessary features.
• Deep Copy:
• Example:
• A deep copy creates a new object and recursively copies all objects
python found in the original.
Copy code • This means that changes to the nested objects in either the original
from abc import ABC, abstractmethod or the copy will not affect the other.
• Deep copies are more time-consuming and memory-intensive
because they involve the creation of new objects for all nested
class Shape(ABC): structures.
@abstractmethod Use Cases:
def area(self): • Shallow Copy: Suitable when a new object with some shared data is
pass needed.
• Deep Copy: Suitable when a completely independent copy of the object is
required.
class Rectangle(Shape):
def __init__(self, width, height):
34. Explain the asymptotic notations in detail and their types with a suitable
self.width = width example program.
self.height = height Asymptotic Notations:
1. Big O (O):
def area(self): • Represents the upper bound of the time complexity.
return self.width * self.height • Describes the worst-case scenario.
• Example: O(n) for a linear time algorithm.
33. Explain in detail about the shallow and Deep copy class with suitable • Example Program:
example.
python
• Describes the lower limit of the algorithm's running time. while temp and temp.data != key:
• It tells us the best-case time complexity, or the minimum time an prev = temp
algorithm will take to complete. temp = temp.next
• Example: Ω(n) for linear search, where the best case is finding the if temp is None:
element at the first position.
return
• Theta:
prev.next = temp.next
• Provides a tight bound on the running time of an algorithm.
temp = None
• It means the time complexity is both O(f(n)) and Ω(f(n)).
• Example: θ(n log n) for merge sort, indicating that the running time
def search(self, key):
grows in a specific pattern based on the input size.
current = self.head
Importance:
while current:
• These notations help in comparing the efficiency of different algorithms. if current.data == key:
• They provide a way to understand the scalability and performance of return True
algorithms under various conditions.
current = current.next
return False
35. Write a program to perform all the operations in single linked list.
Single Linked List Operations:
def display_list(self):
1. Node Class:
temp = self.head
• Represents an element in the linked list.
while temp:
• Contains data and a reference to the next node.
print(temp.data, end=" -> ")
2. LinkedList Class:
temp = temp.next
• Manages the linked list operations like insert, delete, and display.
print("None")
Python Implementation:
python
# Usage
Copy code
llist = LinkedList()
class Node:
llist.insert_at_end(1)
def __init__(self, data):
llist.insert_at_end(2)
self.data = data
llist.insert_at_end(3)
self.next = None
llist.insert_at_beginning(0)
llist.display_list() # Output: 0 -> 1 -> 2 -> 3 -> None
class LinkedList:
llist.delete_node(2)
def __init__(self):
llist.display_list() # Output: 0 -> 1 -> 3 -> None
self.head = None
print(llist.search(3)) # Output: True
print(llist.search(4)) # Output: False
def insert_at_end(self, data):
Explanation:
new_node = Node(data)
• insert_at_end: Adds a new node with the given data at the end of the list.
if not self.head:
• insert_at_beginning: Adds a new node with the given data at the beginning
self.head = new_node of the list.
return • delete_node: Deletes the first occurrence of a node with the given data.
• search: Searches for a node with the given data. return len(self.stack) == 0
• display_list: Prints all the nodes in the list. Python Implementation:
Detailed Steps: python
1. Node Class: Copy code
• __init__ method initializes a node with data and sets the next class Stack:
reference to None.
def __init__(self):
2. LinkedList Class:
self.stack = []
• __init__ method initializes the head of the linked list.
• insert_at_end method traverses the list to find the last node and adds
def push(self, data):
the new node at the end.
self.stack.append(data)
• insert_at_beginning method sets the new node's next reference to
the current head and updates the head to the new node.
• delete_node method finds the node with the specified data, updates def pop(self):
the next reference of the previous node, and deletes the found node. if not self.is_empty():
• search method traverses the list to find the node with the specified return self.stack.pop()
data.
return "Stack is empty"
• display_list method traverses the list and prints the data of each
node followed by an arrow.
def peek(self):
36. What is stack? Explain the various operations to be performed on stack with if not self.is_empty():
suitable example program. return self.stack[-1]
Stack: return "Stack is empty"
• A stack is a linear data structure that follows the Last In First Out (LIFO)
principle.
def is_empty(self):
• It can be visualized as a collection of elements with two main operations:
push (add an element) and pop (remove an element). return len(self.stack) == 0
Operations:
1. Push: def display_stack(self):
• Example:
# Usage
python s = Stack()
Copy code s.push(1)
def push(self, data): s.push(2)
self.stack.append(data) s.push(3)
2. Pop: s.display_stack() # Output: [1, 2, 3]
• Removes and returns the top element from the stack. print(s.peek()) # Output: 3
• Example: print(s.pop()) # Output: 3
python s.display_stack() # Output: [1, 2]
Copy code print(s.is_empty()) # Output: False
def pop(self): s.pop()
if not self.is_empty(): s.pop()
return self.stack.pop() print(s.is_empty()) # Output: True
return "Stack is empty" Explanation:
3. Peek: • push: Adds an element to the top of the stack.
• Returns the top element of the stack without removing it. • pop: Removes and returns the top element of the stack.
• Example: • peek: Returns the top element without removing it.
python • is_empty: Checks if the stack is empty.
Copy code • display_stack: Prints all elements in the stack.
def peek(self): Detailed Steps:
if not self.is_empty(): 1. Stack Class:
return self.stack[-1] • __init__ method initializes an empty list to represent the stack.
return "Stack is empty" • push method appends an element to the end of the list (top of the
stack).
4. IsEmpty:
• pop method removes and returns the last element of the list (top of
• Checks if the stack is empty.
the stack).
• Example:
• peek method returns the last element of the list without removing it.
python
• is_empty method checks if the list is empty.
Copy code
• display_stack method prints the elements in the stack.
def is_empty(self):
Use Cases: • Compare with 8, shift 8 to the right.
• Function Call Management: Stacks are used to manage function calls in • Compare with 2, shift 2 to the right.
programming languages.
• Insert 0 at index 0.
• Expression Evaluation: Stacks are used to evaluate postfix expressions.
• Array: [0, 2, 8, 15, 20, 65, 50, 34]
• Undo Mechanism: Stacks are used to implement undo mechanisms in
5. **Fifth
software applications.
38. Write a program to perform binary search and explain it with example.
37. Write a program to sort the elements using insertion sort and illustrate the
steps to perform the same with the following array elements. A [20, 15, 8, 2, 0, Binary Search:
65, 50, 34]. • Binary search is an efficient algorithm for finding an item from a sorted list
Insertion Sort: of items.
Algorithm: • It works by repeatedly dividing in half the portion of the list that could
contain the item, until you’ve narrowed down the possible locations to just
1. Start from the second element (index 1).
one.
2. Compare the current element with the previous elements.
Algorithm:
3. Shift all the elements greater than the current element to the right.
1. Initialize low to 0 and high to len(arr) - 1.
4. Insert the current element at the correct position.
2. While low is less than or equal to high:
5. Repeat until the array is sorted.
• Compute mid as (low + high) // 2.
Python Implementation:
• If arr[mid] is equal to x, return mid.
python
• If arr[mid] is less than x, set low to mid + 1.
Copy code
• If arr[mid] is greater than x, set high to mid - 1.
def insertion_sort(arr):
3. If x is not found, return -1.
for i in range(1, len(arr)):
Python Implementation:
key = arr[i]
python
j=i-1
Copy code
while j >= 0 and key < arr[j]:
def binary_search(arr, x):
arr[j + 1] = arr[j]
low = 0
j -= 1
high = len(arr) - 1
arr[j + 1] = key
index = (index + i ** 2) % len(hash_table) • The heapify process involves moving the new root element down
the tree to its correct position.
i += 1
• In the worst case, this element might need to be moved from the
hash_table[index] = (key, value)
root to a leaf node.
3. Double Hashing:
• The height of a complete binary tree is log(n), where n is the
• Use a second hash function to determine the interval between number of nodes.
probes.
• Therefore, the heapify operation takes O(log n) time.
• Example:
Conclusion:
python
• The overall time complexity of the extraction operation is O(log n) because
Copy code the dominating factor is the heapify operation.
def double_hashing(hash_table, key, value): Example: Consider a max-heap represented as an array: [50, 30, 40, 10, 20, 35,
index = key % len(hash_table) 25].
while hash_table[index] is not None: • Replace it with the last element (25).
index = (index + step_size) % len(hash_table) • Heapify the array to maintain the heap property.
hash_table[index] = (key, value) • Resulting heap: [40, 30, 35, 10, 20, 25].
Detailed Explanation:
• Linear Probing: 41. Consider the following set of values and use them to build the indicated type
of tree by adding one value at a time in the order listed: V [30, 63, 2, 89, 16, 24,
• A simple and effective method but can lead to clustering where a 19, 52, 27, 9, 4, 45]
group of consecutive occupied slots is formed, leading to increased
search time. (i) binary search tree. (ii) AVL tree. Give an explanation when there is a change in
the root nodes.
• Quadratic Probing:
Binary Search Tree (BST):
• Reduces clustering by spreading out the probe sequence but may
still lead to secondary clustering. • Insert each value maintaining the BST property (left child < parent < right
child).
• Double Hashing:
Steps:
• Provides the best performance by using a secondary hash function to
calculate the probe sequence, minimizing clustering. 1. Insert 30 as root.
Example: Consider a hash table of size 10 and the keys: 22, 33, 44, 55. 2. Insert 63 to the right of 30.
5. Insert 16 to the left of 2. • Explore all neighbors at the present depth before moving on to
nodes at the next depth level.
6. Insert 24 to the right of 16.
• Uses a queue.
7. Insert 19 to the left of 24.
• Example:
• Tree becomes unbalanced, perform right rotation on 16.
python
8. Insert 52 to the left of 63.
Copy code
9. Insert 27 to the right of 24.
def bfs(graph, start):
• Tree becomes unbalanced, perform left rotation on 2.
visited = set()
10. Insert 9 to the right of 16.
queue = [start]
11. Insert 4 to the left of 9.
while queue:
12. Insert 45 to the left of 52.
vertex = queue.pop(0)
AVL Tree:
if vertex not in visited:
visited.add(vertex)
Copy code
print(vertex, end=" ")
16
queue.extend(set(graph[vertex]) - visited)
/ \
2 30
graph = {
/\ / \
'A': ['B', 'C'],
4 9 24 63
'B': ['A', 'D', 'E'],
/\ /\
'C': ['A', 'F'],
19 27 52 89
'D': ['B'],
/
'E': ['B', 'F'],
45
'F': ['C', 'E']
Explanation of Root Node Changes:
}
• When inserting 27, the tree becomes unbalanced at node 2. Perform a left
rotation around 2, making 16 the new root. bfs(graph, 'A')
• When inserting 19, the tree becomes unbalanced at node 16. Perform a Explanation:
right rotation around 16, balancing the tree again.
• DFS:
• Starts at the root and explores as far as possible along each branch for v in graph[u]:
before backtracking.
in_degree[v] -= 1
• Suitable for problems where you need to explore all possible paths
if in_degree[v] == 0:
(e.g., puzzles, mazes).
queue.append(v)
• BFS:
• Starts at the root and explores all neighbors at the current depth
before moving to the next level. if len(topo_order) == len(graph):
• Suitable for problems where the shortest path is required (e.g., return topo_order
unweighted shortest path). else:
Graph Example: Consider the graph: return "Graph has a cycle"
• One possible topological ordering: A, D, B, E, C. • Identifying cut-vertices helps in understanding the weak points in the
network.
Python Implementation:
(c) Linear Algorithm to Determine Biconnectivity:
python
• Use Depth-First Search (DFS) to find articulation points and check for
Copy code biconnectivity.
def topological_sort(graph): Algorithm:
in_degree = {u: 0 for u in graph} 1. Perform DFS and keep track of discovery and low values for each vertex.
for u in graph: 2. A vertex u is an articulation point if:
for v in graph[u]: • u is the root of the DFS tree and has two or more children.
in_degree[v] += 1 • u is not the root and there is a child v of u such that no vertex in the
subtree rooted at v has a back edge to an ancestor of u.
topo_order = [] python
Copy code
topo_order.append(u) children = 0
visited[u] = True in_order_traversal(root.left)
disc[u] = low[u] = time + 1 print(root.val, end=" ")
in_order_traversal(root.right)
for v in graph[u]:
if not visited[v]: # Usage
children += 1 root = Node(1)
dfs(v, u, visited, disc, low, time + 1, ap) root.left = Node(2)
low[u] = min(low[u], low[v]) root.right = Node(3)
root.left.left = Node(4)
if parent is None and children > 1: root.left.right = Node(5)
ap[u] = True in_order_traversal(root) # Output: 4 2 5 1 3
if parent is not None and low[v] >= disc[u]: Pre-order Traversal
ap[u] = True • Algorithm:
elif v != parent: 1. Visit the root.
low[u] = min(low[u], disc[v]) 2. Traverse the left subtree.
3. Traverse the right subtree.
n = len(graph) • Example:
visited = [False] * n python
disc = [float('inf')] * n Copy code
low = [float('inf')] * n def pre_order_traversal(root):
ap = [False] * n if root:
print(root.val, end=" ")
for i in range(n): pre_order_traversal(root.left)
if not visited[i]: pre_order_traversal(root.right)
dfs(i, None, visited, disc, low, 0, ap)
# Usage
if any(ap): pre_order_traversal(root) # Output: 1 2 4 5 3
return False Post-order Traversal
else: • If the token is an operator, pop from the stack to the output list until
the stack is empty or an operator with less precedence is at the top
bucket.values.append(value)
of the stack, then push the token to the stack.
• If the token is (, push it to the stack.
def split_bucket(self, index):
• If the token is ), pop from the stack to the output list until ( is at the
old_bucket = self.buckets[index] top of the stack, then pop ( from the stack.
new_bucket = Bucket(old_bucket.depth + 1) 3. Pop the remaining operators from the stack to the output list.
old_bucket.depth += 1 Python Implementation:
self.buckets.append(new_bucket) python
for value in old_bucket.values[:]: Copy code
if self.hash(value) == len(self.buckets) - 1: def infix_to_postfix(expression):
old_bucket.values.remove(value) precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '%': 2, '(': 0}
new_bucket.values.append(value) stack = []
if old_bucket.depth > self.global_depth: output = []
self.global_depth += 1 tokens = expression.replace("(", " ( ").replace(")", " ) ").split()
self.buckets.extend([None] * len(self.buckets))
for token in tokens:
def display(self): if token.isalnum():
for i, bucket in enumerate(self.buckets): output.append(token)
if bucket: elif token == '(':
print(f"Bucket {i}: depth={bucket.depth}, values={bucket.values}") stack.append(token)
elif token == ')':
# Usage top_token = stack.pop()
eht = ExtendibleHashTable() while top_token != '(':
elements = [2, 3, 5, 7, 11, 17, 19, 23, 29, 31] output.append(top_token)
for element in elements: top_token = stack.pop()
eht.insert(element) else:
eht.display() while stack and precedence[stack[-1]] >= precedence[token]:
Diagram for Extendible Hashing:
output.append(stack.pop()) • Elements with higher priority are dequeued before elements with lower
priority.
stack.append(token)
Diagram:
while stack:
Copy code
output.append(stack.pop())
Priority Queue:
+---------------------+
return " ".join(output)
| Elements | Priority |
+---------------------+
# Usage
| A | 3 |
expression = "A - ( B / C + ( D % E * F ) / G ) * H"
+---------------------+
postfix = infix_to_postfix(expression)
| B | 2 |
print(postfix) # Output: A B C / D E % F * G / + H * -
+---------------------+
Postfix Evaluation
| C | 1 |
Algorithm:
+---------------------+
1. Initialize an empty stack.
Operations
2. Iterate over each token in the postfix expression:
1. Insert:
• If the token is an operand, push it to the stack.
• Add an element to the queue with a given priority.
• If the token is an operator, pop the necessary number of operands
from the stack, perform the operation, and push the result back to • Example:
the stack.
python
3. The result is the final value in the stack.
Copy code
Python Implementation:
def insert(pq, element, priority):
python
pq.append((element, priority))
Copy code
pq.sort(key=lambda x: x[1])
def evaluate_postfix(expression):
2. Extract-Max (or Extract-Min):
stack = []
• Remove and return the element with the highest (or lowest) priority.
tokens = expression.split()
• Example:
python
def peek(self):
return self.pq[-1]
def is_empty(self):
return len(self.pq) == 0
# Usage
pq = PriorityQueue()
pq.insert('A', 3)
pq.insert('B', 2)
pq.insert('C', 1)
print(pq.extract_max()) # Output: ('A', 3)
print(pq.peek()) # Output: ('B', 2)
print(pq.is_empty()) # Output: False
55. Applications of Stack and Queue
Applications of Stack:
1. Function Call Management: Used in programming languages to keep track
of function calls.
2. Expression Evaluation: Used in algorithms to evaluate postfix expressions.
3. Syntax Parsing: Used in compilers to parse expressions, program blocks,
etc.
4. Undo Mechanism: Used in applications like text editors to implement
undo actions.
5. Backtracking: Used in algorithms like maze solving, game playing, etc.
Applications of Queue:
1. Scheduling: Used in operating systems to manage processes in a scheduling
queue.
2. Buffering: Used in data streaming applications to buffer data.
3. Breadth-First Search (BFS): Used in graph algorithms to explore nodes
level by level.
4. Print Spooling: Used in print management systems to manage print jobs.
5. Message Queues: Used in communication systems to manage messages
between processes or systems.