MCS-021 Data and File Structures
MCS-021 Data and File Structures
Here’s a C program that accepts two polynomials as input and prints the resultant polynomial due to the
multiplication of the input polynomials.
Explanation:
In this program:
We represent each polynomial as an array where the index represents the power of the variable (x) and
the value at each index represents the coefficient of that power.
We perform polynomial multiplication by multiplying each term of the first polynomial by every term
of the second polynomial and store the results in the resulting polynomial array.
Code:
#include <stdio.h> language-c
int main() {
int poly1Degree, poly2Degree;
return 0;
}
Input:
Enter the degree of the first polynomial: 2
Enter the coefficients of the first polynomial (from degree 0 to 2):
Coefficient of x^0: 1
Coefficient of x^1: 2
Coefficient of x^2: 1
Enter the degree of the second polynomial: 1
Enter the coefficients of the second polynomial (from degree 0 to 1):
Coefficient of x^0: 1
Coefficient of x^1: 3
Output:
Resultant polynomial after multiplication: x^3 + 5x^2 + 5x + 1
Q2. Write a program in ‘C’ to create a single linked list and perform the
following operations on it:
- (i) Insert a new node at the beginning, in the middle or at the end of the
linked list.
- (iv) Sort and display data of the linked list in ascending order.
Here is a complete C program to create a singly linked list and perform the specified operations:
#include <stdlib.h>
// (i) Insert a new node at the beginning, in the middle or at the end of the linked list.
Function to insert a node in the middle
void insertInMiddle(struct Node** head, int data, int position) {
struct Node* newNode = createNode(data);
if (position == 1) {
insertAtBeginning(head, data);
return;
}
struct Node* temp = *head;
for (int i = 1; i < position - 1 && temp != NULL; i++)
temp = temp->next;
if (temp == NULL) {
printf("Position out of range\n");
return;
}
newNode->next = temp->next;
temp->next = newNode;
}
// (ii) Delete a node from the linked list. Function to delete a node
void deleteNode(struct Node** head, int key) {
struct Node* temp = *head;
struct Node* prev = NULL;
// (iii) Display the linked list in reverse order. Function to reverse the linked list
recursively
void displayReverse(struct Node* head) {
if (head == NULL)
return;
displayReverse(head->next);
printf("%d -> ", head->data);
}
// (iv) Sort and display data of the linked list in ascending order. Function to sort the
linked list
void sortList(struct Node** head) {
struct Node* current = *head;
struct Node* index = NULL;
int temp;
if (head == NULL)
return;
// (v) Function to Count the number of items stored in a single linked list
int countNodes(struct Node* head) {
int count = 0;
struct Node* temp = head;
while (temp != NULL) {
count++;
temp = temp->next;
}
return count;
}
do {
printf("\n\nMenu:\n");
printf("1. Insert at Beginning\n");
printf("2. Insert at End\n");
printf("3. Insert in Middle\n");
printf("4. Delete a Node\n");
printf("5. Display in Reverse\n");
printf("6. Sort List\n");
printf("7. Count Nodes\n");
printf("8. Display List\n");
printf("9. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case 1:
printf("Enter value to insert at beginning: ");
scanf("%d", &value);
insertAtBeginning(&head, value);
break;
case 2:
printf("Enter value to insert at end: ");
scanf("%d", &value);
insertAtEnd(&head, value);
break;
case 3:
printf("Enter value to insert: ");
scanf("%d", &value);
printf("Enter position to insert: ");
scanf("%d", &position);
insertInMiddle(&head, value, position);
break;
case 4:
printf("Enter value to delete: ");
scanf("%d", &value);
deleteNode(&head, value);
break;
case 5:
printf("Linked List in reverse order: ");
displayReverse(head);
printf("NULL\n");
break;
case 6:
sortList(&head);
printf("Sorted list: ");
displayList(head);
break;
case 7:
printf("Number of nodes in the list: %d\n", countNodes(head));
break;
case 8:
printf("Linked List: ");
displayList(head);
break;
case 9:
printf("Exiting...\n");
break;
default:
printf("Invalid choice!\n");
}
} while (choice != 9);
return 0;
}
Explanation of Operations:
1. Insertion of Node:
You can insert a node at the beginning, middle, or end using options 1, 2, and 3.
2. Deletion of Node:
Deletes a node with a specified value from the linked list (option 4).
3. Display Reverse:
Recursively displays the linked list in reverse order (option 5).
4. Sorting:
Sorts the list in ascending order and displays it (option 6).
5. Counting Nodes:
Counts and prints the number of nodes present in the list (option 7).
6. Display List:
Displays the linked list in regular order (option 8).
Sample Input/Output:
Menu:
1. Insert at Beginning
2. Insert at End
3. Insert in Middle
4. Delete a Node
5. Display in Reverse
6. Sort List
7. Count Nodes
8. Display List
9. Exit
Enter your choice: 1
Enter value to insert at beginning: 10
Menu:
1. Insert at Beginning
2. Insert at End
3. Insert in Middle
4. Delete a Node
5. Display in Reverse
6. Sort List
7. Count Nodes
8. Display List
9. Exit
Enter your choice: 8
Linked List: 10 -> NULL
- (i) Insert a new node at the beginning, in the middle or at the end of the
linked list.
- (iii) Sort and display data of the doubly linked list in ascending order.
- (v) Calculate the sum of all even integer numbers, stored in the doubly
linked list.
Here is a C program to create a doubly linked list to store integer values and perform the specified
operations:
#include <stdlib.h>
if (temp->prev != NULL) {
temp->prev->next = temp->next;
} else {
*head = temp->next;
}
if (temp->next != NULL) {
temp->next->prev = temp->prev;
}
free(temp);
}
if (*head == NULL)
return;
do {
printf("\n\nMenu:\n");
printf("1. Insert at Beginning\n");
printf("2. Insert at End\n");
printf("3. Insert in Middle\n");
printf("4. Delete a Node\n");
printf("5. Sort List\n");
printf("6. Count Nodes\n");
printf("7. Sum of Even Numbers\n");
printf("8. Display List\n");
printf("9. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case 1:
printf("Enter value to insert at beginning: ");
scanf("%d", &value);
insertAtBeginning(&head, value);
break;
case 2:
printf("Enter value to insert at end: ");
scanf("%d", &value);
insertAtEnd(&head, value);
break;
case 3:
printf("Enter value to insert: ");
scanf("%d", &value);
printf("Enter position to insert: ");
scanf("%d", &position);
insertInMiddle(&head, value, position);
break;
case 4:
printf("Enter value to delete: ");
scanf("%d", &value);
deleteNode(&head, value);
break;
case 5:
sortList(&head);
printf("Sorted list: ");
displayList(head);
break;
case 6:
printf("Number of nodes in the list: %d\n", countNodes(head));
break;
case 7:
printf("Sum of even numbers: %d\n", sumEvenNumbers(head));
break;
case 8:
printf("Doubly Linked List: ");
displayList(head);
break;
case 9:
printf("Exiting...\n");
break;
default:
printf("Invalid choice!\n");
}
} while (choice != 9);
return 0;
}
Explanation of Operations:
1. Insertion of Node:
Inserts a node at the beginning, middle, or end using options 1, 2, and 3.
2. Deletion of Node:
Deletes a node with a specified value from the doubly linked list (option 4).
3. Sorting:
Sorts the list in ascending order and displays it (option 5).
4. Counting Nodes:
Counts and prints the number of nodes present in the doubly linked list (option 6).
5. Sum of Even Numbers:
Calculates and prints the sum of all even integer numbers stored in the list (option 7).
6. Display List:
Displays the doubly linked list in forward order (option 8).
Sample Input/Output:
Menu:
1. Insert at Beginning
2. Insert at End
3. Insert in Middle
4. Delete a Node
5. Sort List
6. Count Nodes
7. Sum of Even Numbers
8. Display List
9. Exit
Enter your choice: 1
Enter value to insert at beginning: 15
Menu:
1. Insert at Beginning
2. Insert at End
3. Insert in Middle
4. Delete a Node
5. Sort List
6. Count Nodes
7. Sum of Even Numbers
8. Display List
9. Exit
Enter your choice: 8
Doubly Linked List: 15 <-> NULL
A Dequeue (short for Double-Ended Queue) is a data structure that allows insertion and deletion of
elements from both ends — front and rear. Unlike regular queues where insertion happens at the rear and
deletion happens at the front, a dequeue provides more flexibility by supporting the following operations:
Types of Dequeues:
1. Input-Restricted Dequeue: Allows insertion only at one end but deletion at both ends.
2. Output-Restricted Dequeue: Allows deletion only from one end but insertion at both ends.
Operations on a Dequeue
1. insertFront(): Insert an element at the front of the dequeue.
2. insertRear(): Insert an element at the rear of the dequeue.
3. deleteFront(): Delete an element from the front of the dequeue.
4. deleteRear(): Delete an element from the rear of the dequeue.
5. isFull(): Check if the dequeue is full.
6. isEmpty(): Check if the dequeue is empty.
Q5. Draw the binary tree for which the traversal sequences are given
as follows:
Pre-order traversal (Root, Left, Right): Visits the root node first, followed by the left subtree, and
then the right subtree.
In-order traversal (Left, Root, Right): Visits the left subtree first, then the root node, and then the
right subtree.
Post-order traversal (Left, Right, Root): Visits the left subtree first, followed by the right subtree,
and finally the root node.
By using both pre-order and in-order (or post-order and in-order) sequences, we can uniquely
reconstruct the binary tree.
(i)
Given:
Pre-order: A B D E F C G H I J K
In-order: B E D F A C I H K J G
A
/ \
B C
\ \
D G
/ \ / \
E F H J
\ \
I K
(ii)
Given:
Post-order: I J H D K E C L M G F B A
In-order: I H J D C K E A F L G M B
A
/ \
C B
/ \
D F
/ \ / \
H E L G
/ \ / \
I J M B
\
K
Here’s a C program that implements a Binary Search Tree (BST) and provides functions to traverse and
display it in Inorder, Preorder, and Postorder:
#include <stdlib.h>
// Definition of Node for BST
struct Node {
int data;
struct Node* left;
struct Node* right;
};
// Main function
int main() {
struct Node* root = NULL;
int n, data;
return 0;
}
Explanation:
1. Node Structure: A Node structure contains an integer data and pointers to the left and right
child.
2. Insert Function: Inserts nodes in the correct position following the binary search tree property
(left child is smaller, right child is larger).
3. Inorder Traversal: Recursively visits the left subtree, the root, and then the right subtree.
4. Preorder Traversal: Visits the root, then recursively the left and right subtrees.
5. Postorder Traversal: Recursively visits the left and right subtrees, then the root.
Example Output:
Enter the number of nodes: 5
Enter the values to be inserted into BST:
50 30 20 40 70
Inorder Traversal: 20 30 40 50 70
Preorder Traversal: 50 30 20 40 70
Postorder Traversal: 20 40 30 70 50
This program inserts the given nodes into the BST and prints the traversals as per the requirements.
Q7. Define AVL tree. Create an AVL tree for the following list of data if
the data are inserted in the order in an empty AVL tree.
12, 5, 15, 20, 35, 8, 2, 40, 14, 24, 27, 45, 50, 3, 4
12, 5, 15, 20, 35, 8, 2, 40, 14, 24, 27, 45, 50, 3, 4
#include <stdlib.h>
// Right Rotate
struct Node* rightRotate(struct Node* y) {
struct Node* x = y->left;
struct Node* T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right)) + 1;
x->height = max(height(x->left), height(x->right)) + 1;
// Left Rotate
struct Node* leftRotate(struct Node* x) {
struct Node* y = x->right;
struct Node* T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right)) + 1;
y->height = max(height(y->left), height(y->right)) + 1;
// Recursive function to insert a node in the subtree rooted with node and returns the new
root of the subtree
struct Node* insert(struct Node* node, int data) {
// 1. Perform the normal BST insertion
if (node == NULL)
return createNode(data);
// 3. Get the balance factor of this ancestor node to check whether this node became
unbalanced
int balance = getBalance(node);
// Function to find the node with minimum value (used during deletion)
struct Node* minValueNode(struct Node* node) {
struct Node* current = node;
// Loop down to find the leftmost leaf
while (current->left != NULL)
current = current->left;
return current;
}
// Recursive function to delete a node with given key from subtree with given root and
returns new root of subtree
struct Node* deleteNode(struct Node* root, int data) {
// STEP 1: PERFORM STANDARD BST DELETE
if (root == NULL)
return root;
else {
// Node with only one child or no child
if ((root->left == NULL) || (root->right == NULL)) {
struct Node* temp = root->left ? root->left : root->right;
// No child case
if (temp == NULL) {
temp = root;
root = NULL;
} else // One child case
*root = *temp; // Copy the contents of the non-empty child
free(temp);
} else {
// Node with two children: Get the inorder successor (smallest in the right
subtree)
struct Node* temp = minValueNode(root->right);
// STEP 3: GET THE BALANCE FACTOR OF THIS NODE TO CHECK WHETHER THIS NODE BECAME
UNBALANCED
int balance = getBalance(root);
// If this node becomes unbalanced, then there are 4 cases
return root;
}
// Main function
int main() {
struct Node* root = NULL;
// Deleting 2, 4, 5, and 12
root = deleteNode(root, 2);
root = deleteNode(root, 4);
root = deleteNode(root, 5);
root = deleteNode(root, 12);
return 0;
}
Explanation:
1. Node Structure: Each node contains the data, left and right pointers, and height.
2. Insert: Inserts data into the AVL tree, balancing the tree if necessary using rotations (left, right, left-
right, or right-left).
3. Delete:
Output:
Inorder traversal of the AVL tree: 2 3 4 5 8 12 14 15 20 24 27 35 40 45 50
Inorder traversal after deletions: 3 8 14 15 20 24 27 35 40 45 50
In this program, after inserting the nodes and performing the deletions, the AVL tree remains balanced, as
demonstrated by the inorder traversal output.
B-tree Definition:
A B-tree is a self-balancing tree data structure that maintains sorted data and allows efficient insertion,
deletion, and search operations. It is commonly used in databases and file systems. Unlike binary search
trees, B-trees can have multiple keys in each node and multiple children. B-trees help reduce the number of
disk accesses required during search operations.
Properties of B-trees:
1. Order: The order m of a B-tree defines the maximum number of children each node can have. In a
B-tree of order m :
Each internal node can have at most m children.
Each internal node (except the root) must have at least ⌈m/2⌉ children.
The root must have at least 2 children if it is not a leaf.
A node can contain at most m-1 keys.
All leaves appear on the same level.
2. Keys:
Each internal node contains n keys, where ⌈m/2⌉ - 1 ≤ n ≤ m - 1 .
Keys within a node are arranged in ascending order.
3. Search: Searching in a B-tree starts from the root and follows a path that resembles binary search
but works across multiple keys and children.
4. Insertion:
When a node is full (i.e., it has m-1 keys), it is split into two nodes. The middle key is moved up
to the parent node.
This process may propagate upwards, potentially causing the root to split and increase the
height of the tree.
5. Deletion:
Deleting a key may require merging nodes or borrowing keys from siblings to maintain the
properties of the B-tree.
Sequence to insert:
12, 5, 15, 20, 60, 45, 35, 40, 25, 8, 7, 55, 50, 66, 65, 80
Deletions:
1. Delete 5: Remove 5 from the left child, now it becomes [7, 8, 12].
2. Delete 12: Remove 12 from the left child, now it becomes [7, 8].
3. Delete 8: Remove 8 from the left child. After deletion, we need to merge nodes since the node
becomes underfull (fewer than 2 keys). The result is:
Left Child: [7]
4. Delete 20: Remove 20 from the middle left child. After deletion, the middle left child becomes [25,
35].
Step-by-Step Process:
1. Initialize:
Set the initial distances from 'S' to all other vertices as infinite ( ∞ ), except for the starting
vertex 'S' itself, which has a distance of 0.
Initial distances:
S = 0, A = ∞, B = ∞, C = ∞, D = ∞
The current node is 'S'. Explore all edges from 'S' and update the distances to its neighbors.
From 'S' to 'A': 10 units (S → A = 10)
From 'S' to 'C': 5 units (S → C = 5)
From 'S' to 'D': 7 units (S → D = 7)
Updated distances:
S = 0, A = 10, B = ∞, C = 5, D = 7
The next node is the one with the smallest distance that hasn't been processed yet. This is 'C'
(distance 5).
Explore all edges from 'C'.
From 'C' to 'A': C → A = 5 + 3 = 8 (updated because 8 < 10)
From 'C' to 'D': C → D = 5 + 2 = 7 (already the same as current distance to D)
Updated distances:
S = 0, A = 8, B = ∞, C = 5, D = 7
Updated distances:
S = 0, A = 8, B = 13, C = 5, D = 7
Updated distances:
S = 0, A = 8, B = 9, C = 5, D = 7
Shortest Paths:
S → A: S → C → A (total distance = 8)
S → B: S → C → A → B (total distance = 9)
S → C: S → C (total distance = 5)
S → D: S → D (total distance = 7)
To apply Prim's Algorithm to the given graph and find the Minimum Spanning Tree (MST), we will
proceed step by step.
Graph Data:
Vertices: 0, 1, 2, 3, 4, 5, 6, 7, 8
Edges with weights (u - v: weight):
0 - 1: 4, 0 - 7: 8
1 - 7: 11, 1 - 2: 8
7 - 8: 7, 7 - 6: 1, 7 - 0: 8
2 - 8: 2, 2 - 3: 7, 2 - 5: 4
8 - 6: 6, 8 - 2: 2, 8 - 7: 7
6 - 5: 2, 6 - 7: 1, 6 - 8: 6
3 - 4: 9, 3 - 5: 14
5 - 4: 10, 5 - 6: 2
Execution:
0 - 1: 4
0 - 1: 4
0 - 7: 8
0 - 1: 4
0 - 7: 8
7 - 6: 1
0 - 1: 4
0 - 7: 8
7 - 6: 1
6 - 5: 2
0 - 1: 4
0 - 7: 8
7 - 6: 1
6 - 5: 2
6 - 8: 6
0 - 1: 4
0 - 7: 8
7 - 6: 1
6 - 5: 2
6 - 8: 6
2 - 8: 2
0 - 1: 4
0 - 7: 8
7 - 6: 1
6 - 5: 2
6 - 8: 6
2 - 8: 2
2 - 3: 7
0 - 1: 4
0 - 7: 8
7 - 6: 1
6 - 5: 2
6 - 8: 6
2 - 8: 2
2 - 3: 7
3 - 4: 9
Let’s go through the intermediate steps of both algorithms and analyze their time complexity.
Insertion Sort
Insertion Sort works by building a sorted section of the list one element at a time by repeatedly inserting
the next unsorted element into its correct position in the sorted section.
Initial List:
12, 5, 2, 15, 25, 30, 45, 8, 17, 50, 3, 7
Step-by-step Process:
Start with the second element (5). Compare with 12, and since 5 < 12, move 12 to the right and insert 5
at the start.
5, 12, 2, 15, 25, 30, 45, 8, 17, 50, 3, 7
Next, take 2. Compare with 12 and 5, shift them to the right and insert 2 at the start.
2, 5, 12, 15, 25, 30, 45, 8, 17, 50, 3, 7
Take 8. Compare it with 45, 30, 25, 15, and so on. Shift all these elements to the right and insert 8
between 5 and 12.
2, 5, 8, 12, 15, 25, 30, 45, 17, 50, 3, 7
Take 17. Shift 45 and 30 to the right, then insert 17 between 15 and 25.
2, 5, 8, 12, 15, 17, 25, 30, 45, 50, 3, 7
Take 3. Shift all the elements larger than 3 to the right and insert 3 at the second position.
2, 3, 5, 8, 12, 15, 17, 25, 30, 45, 50, 7
Finally, take 7. Shift 50, 45, 30, 25, 17, 15, 12, and 8 to the right, then insert 7 between 5 and 8.
2, 3, 5, 7, 8, 12, 15, 17, 25, 30, 45, 50
Selection Sort
Selection Sort works by selecting the smallest element from the unsorted portion of the list and swapping it
with the first element of the unsorted portion. Then repeat the process for the next unsorted part of the list.
Initial List:
12, 5, 2, 15, 25, 30, 45, 8, 17, 50, 3, 7
Step-by-step Process:
In the first pass, find the smallest element (2) and swap it with the first element (12).
2, 5, 12, 15, 25, 30, 45, 8, 17, 50, 3, 7
In the fourth pass, the next smallest element is 7. Swap 7 with 15.
2, 3, 5, 7, 25, 30, 45, 8, 17, 50, 12, 15
In the fifth pass, the next smallest element is 8. Swap 8 with 25.
2, 3, 5, 7, 8, 30, 45, 25, 17, 50, 12, 15
In the sixth pass, the next smallest element is 12. Swap 12 with 30.
2, 3, 5, 7, 8, 12, 45, 25, 17, 50, 30, 15
In the seventh pass, the next smallest element is 15. Swap 15 with 45.
2, 3, 5, 7, 8, 12, 15, 25, 17, 50, 30, 45
In the eighth pass, the next smallest element is 17. Swap 17 with 25.
2, 3, 5, 7, 8, 12, 15, 17, 25, 50, 30, 45
In the ninth pass, the next smallest element is 25. No swap is needed.
2, 3, 5, 7, 8, 12, 15, 17, 25, 50, 30, 45
In the tenth pass, the next smallest element is 30. Swap 30 with 50.
2, 3, 5, 7, 8, 12, 15, 17, 25, 30, 50, 45
In the eleventh pass, the next smallest element is 45. Swap 45 with 50.
2, 3, 5, 7, 8, 12, 15, 17, 25, 30, 45, 50
Insertion Sort:
Best case: O(n) - When the array is already sorted.
Worst case: O(n²) - When the array is sorted in reverse order.
Average case: O(n²) - When the array is randomly ordered.
Selection Sort:
Best case: O(n²) - Selection sort always takes O(n²) because it scans the entire list to find the
minimum.
Worst case: O(n²) - Selection sort always takes O(n²), regardless of input.
Average case: O(n²) - The algorithm is insensitive to the initial ordering of the list.
Both algorithms sort the list in ascending order, but Insertion Sort tends to perform better on nearly
sorted data, whereas Selection Sort performs the same regardless of the initial order of the data.
Q12: Heap Tree and Heap Sort
In a Max Heap, the value of each node is greater than or equal to the values of its children, making the
largest element the root.
In a Min Heap, the value of each node is smaller than or equal to its children, making the smallest
element the root.
We will build the Max Heap by inserting elements one by one and ensuring the heap property is maintained
by heapifying the tree.
10
2. Insert 20:
Compare 20 with 10. Since 20 > 10, swap them.
Heap:
20
/
10
3. Insert 5:
Heap:
20
/ \
10 5
4. Insert 25:
Compare 25 with 10. Swap 25 and 10. Then compare 25 with 20. Swap 25 and 20.
Heap:
25
/ \
20 5
/
10
5. Insert 30:
Compare 30 with 20. Swap 30 and 20. Then compare 30 with 25. Swap 30 and 25.
Heap:
30
/ \
25 5
/
10 20
6. Insert 18:
Heap:
30
/ \
25 18
/ \
10 20 5
7. Insert 3:
Heap:
30
/ \
25 18
/ \ \
10 20 5
/
3
8. Insert 70:
Compare 70 with 10. Swap them. Then compare 70 with 25. Swap them. Then compare 70 with 30. Swap 70
and 30.
Heap:
70
/ \
30 18
/ \ \
25 20 5
/ \
3 10
9. Insert 55:
Compare 55 with 25. Swap them. Then compare 55 with 30. Swap them.
Heap:
70
/ \
55 18
/ \ \
30 20 5
/ \
3 10 25
70
/ \
55 18
/ \ \
45 20 5
/ \
3 10 25
70
/ \
55 18
/ \ \
45 20 5
/ \ \
3 10 25 12
70
/ \
55 18
/ \ \
45 24 5
/ \ \
3 10 25 12
Heap Sort has a consistent time complexity of O(n log n) in all cases since the heap operations are always
logarithmic and occur for every element.
The 2-way merge sort splits the array into two parts, sorts each part, and then merges the two sorted
arrays.
return 0;
}
Explanation:
1. merge() function:
This function merges two subarrays: L[] (left) and R[] (right).
It compares elements from both arrays and stores the smaller one into the original array
arr[] .
2. mergeSort() function:
This is a recursive function that splits the array in two halves, sorts them, and then merges
them back.
3. printArray() function:
This function is used to display the array before and after sorting.
Sample Output:
Given array:
12 11 13 5 6 7
Sorted array:
5 6 7 11 12 13
Time Complexity:
Best Case: O(n log n)
Worst Case: O(n log n)
Average Case: O(n log n)
Merge sort has a consistent time complexity of O(n log n) for all cases since it always divides the array into
two and merges them, which is logarithmic in nature.
Q14. What is Splay tree? Explain the Zig zag and Zag zig rotations in
Splay tree with the help of a suitable example.
Splay Tree:
A splay tree is a self-adjusting binary search tree where recently accessed elements are moved closer to the
root through a series of rotations. This helps in optimizing access time for frequently accessed elements,
making the tree adaptively efficient. The key operation of a splay tree is splaying, which involves performing
rotations to move a particular node to the root.
Types of Rotations:
There are three types of rotations performed during splaying:
Example:
10
/
5
\
8
Node 8 is the right child of 5 (left child of 10), so we need to perform a Zig-Zag rotation.
Steps:
Example:
10
\
15
/
12
Steps:
Example:
Suppose we insert a new node into the following Red-Black Tree:
Before Insertion:
10 (Black)
/ \
5 (Red) 20 (Black)
Let’s insert 15 :
2. Since 15 is red and its parent 20 is black, no property is violated. Thus, no further changes are
required.
10 (Black)
/ \
5 (Red) 20 (Black)
/
15 (Red)
\
25 (Red)
Here, the new node 25 is red and its parent 15 is also red, violating the Red-Black Tree property that no two
consecutive nodes can be red. To fix this:
Example:
Consider the tree:
10 (Black)
/ \
5 (Black) 20 (Black)
/
15 (Red)
If we delete node 15 :
10 (Black)
/ \
5 (Black) 20 (Black)
Since 15 was red, its deletion doesn’t violate any Red-Black Tree properties.
10 (Black)
\
20 (Black)
Now, node 10 has one black child and one NIL (black) child, maintaining the black height. No further
adjustments are needed.
In more complex scenarios, a series of rotations and recoloring operations may be required to fix the tree
after deletions.
Rotations:
Left Rotation: Used when the right subtree is "heavier" or needs to be balanced with the left subtree.
Right Rotation: Used when the left subtree is "heavier" or needs balancing.
Time Complexity:
Insertion/Deletion: O(log n)
Search: O(log n)
The balancing properties of the Red-Black Tree ensure that these operations remain efficient even in the
worst case.
Characteristics:
Records are accessed directly through a hash function applied to the record's key.
No sequential search is required; data can be accessed in constant time ( O(1) ), making this method
efficient for large databases.
Collisions may occur when two different keys map to the same location, which is handled by
techniques like open addressing or chaining.
Advantages:
Fast access to records.
Efficient when the key is known and direct access is required.
Disadvantages:
Handling collisions can be complex.
Wasted space may occur if many hash locations are unused (sparse distribution).
Inefficient for range queries (when you need to access records sequentially).
Indexed Sequential File Organization:
Indexed sequential file organization combines the features of both sequential and direct access file
organizations. It maintains records in a sequential order but adds an index to speed up access to records.
Structure:
1. Data File: Contains records in sequential order based on a key field (like a sorted list).
2. Index File: Contains key fields and pointers to records in the data file. This acts like a lookup table
that speeds up searching for specific records.
Characteristics:
Data is stored sequentially (sorted by key).
An index is maintained, which provides direct access to a subset of records, reducing the time to
search.
If a key is not found directly in the index, a sequential search is performed within a block of records.
Advantages:
Faster access to records due to the use of an index.
Supports both sequential and direct access, making it versatile for various use cases.
Efficient for range queries, as records are sorted.
Disadvantages:
More storage is required to maintain the index.
Overhead for maintaining the index during insertions and deletions.
Slower access compared to purely direct file organization, especially if the index becomes large.
Comparison:
Feature Direct File Organization Indexed Sequential File
Organization
Access Method Direct (through hashing) Sequential + Indexed
Search Time ( O(1) ) (constant time) Fast via index, sequential search for non-
indexed records
Efficient for Exact record access Range queries and partial key searches
Index Maintenance Not required Required
Storage Efficiency May waste space due to collisions or Uses extra storage for the index
unused hash locations
Insertion/Deletion Hash collisions must be handled Index needs updating
Complexity
Use Cases Fast lookups when key is known Mixed queries (exact + range queries)