DS-Question Bank UNIT 5 Solution
DS-Question Bank UNIT 5 Solution
DS-Question Bank UNIT 5 Solution
Q
No UNIT 5
.
Explain Binary Tree. Explain Representation of Binary tree. Also explain different operation that can be
1 performed on Binary tree.
Solution:
A binary tree is a data structure in which each node has at most two children, referred to as the
left and right child. It is used to represent hierarchical data and is foundational in various
algorithms, such as searching and sorting.
Representation of Binary Tree in C
In C, a binary tree can be represented using a structure that includes data and pointers to the left
and right children. Here's how you can define a binary tree node:
#include <stdio.h>
#include <stdlib.h>
// Define the structure for a tree node
struct Node
{
int data;
struct Node* left;
struct Node* right;
};
// Function to create a new node
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*) malloc (sizeof (struct Node));
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
Operations on Binary Tree
Here are some common operations that can be performed on a binary tree, along with their
implementations in C:
1. Insertion: Inserting a new node into the binary tree.
For simplicity, here’s how to insert a node in a binary search tree (BST):
struct Node* insert(struct Node* root, int data)
{
if (root == NULL)
{
return createNode(data);
}
if (data < root->data)
{
root->left = insert(root->left, data);
}
else
{
root->right = insert(root->right, data);
}
return root;
}
2.Traversal: Different methods to traverse the tree.
• In-order Traversal (Left, Root, Right):
Explain the differences between a binary search tree (BST) and heap. For the given sequence of numbers,
2 construct a heap and a BST: 34, 23, 67, 45, 12, 54, 87, 43, 98, 75, 84, 93, 31
Solution:
Differences Between a Binary Search Tree (BST) and a Heap
Binary Search Tree (BST):
1. Structure: A BST is a binary tree where each node has at most two children, and the left child
contains values less than the parent node, while the right child contains values greater than
the parent node.
2. Ordering: The in-order traversal of a BST results in a sorted sequence of values.
3. Use Cases: BSTs are typically used for dynamic set operations like searching, inserting, and
deleting. They allow efficient searching with average time complexity of O(log n) if balanced.
4. Balance: If the tree becomes unbalanced (e.g., inserting sorted data), it can degrade to a
linked list with O(n) time complexity for search operations.
Heap:
1. Structure: A heap is a complete binary tree that satisfies the heap property: for a max-heap,
every parent node has a value greater than or equal to its children; for a min-heap, every
parent node has a value less than or equal to its children.
2. Ordering: Heaps do not maintain a strict ordering of all elements; only the parent-child
relationship is preserved.
3. Use Cases: Heaps are often used to implement priority queues, where the highest (or lowest)
priority element can be accessed in O(1) time, and insertion and deletion operations can be
done in O(log n) time.
4. Implementation: Heaps are often implemented using arrays, making them efficient in terms
of space.
Construction of a Heap and a BST from the Given Sequence
Given the sequence of numbers: 34, 23, 67, 45, 12, 54, 87, 43, 98, 75, 84, 93, 31.
1. Constructing a Binary Search Tree (BST)
Here’s how to construct a BST in C:
#include <stdio.h>
#include <stdlib.h>
int main() {
int values[] = {34, 23, 67, 45, 12, 54, 87, 43, 98, 75, 84, 93, 31};
int n = sizeof(values) / sizeof(values[0]);
struct BSTNode* root = NULL;
// In-order traversal
printf("In-order traversal of BST: ");
inorderBST(root);
printf("\n");
return 0;
}
2. Constructing a Max Heap
Here’s how to construct a max heap in C:
#include <stdio.h>
#include <stdlib.h>
// Heapify up
for (int i = heap->size / 2 - 1; i >= 0; i--) {
heapifyDown(heap, i);
}
}
int main() {
int values[] = {34, 23, 67, 45, 12, 54, 87, 43, 98, 75, 84, 93, 31};
int n = sizeof(values) / sizeof(values[0]);
// Clean up
free(heap->array);
free(heap);
return 0;
}
Explanation of the Code
1. BST Code:
o Defines a structure for a BST node.
o Implements functions to create nodes, insert into the BST, and perform in-order
traversal.
o In the main function, it constructs the BST from the provided values and prints the in-
order traversal.
2. Max Heap Code:
o Defines a structure for a max heap.
o Implements functions to create the heap, insert values, and heapify.
o In the main function, it constructs the max heap from the provided values and prints
the heap.
3 Can you find a unique tree when any two traversals are given? Using the following traversals construct the
corresponding binary tree:
INORDER: H K D B I L E A F C M J G
PREORDER: A B D H K E I L C F G J M
Also find the Post Order traversal of obtained tree.
Solution:
To construct a binary tree from given traversals, we can use the properties of the preorder and
inorder traversals.
Given Traversals
• Inorder: H K D B I L E A F C M J G
• Preorder: A B D H K E I L C F G J M
Steps to Construct the Binary Tree
1. Identify the Root: The first element of the preorder traversal is always the root of the tree.
In this case, A is the root.
2. Split Inorder Traversal: Find the index of A in the inorder traversal. This index will help us
split the inorder list into left and right subtrees:
o Left Subtree: Elements before A in inorder
o Right Subtree: Elements after A in inorder
Inorder split:
o Left Subtree: H K D B I L E
o Right Subtree: F C M J G
3. Recursive Construction: We recursively apply the same process for the left and right subtrees
using the remaining elements in the preorder list:
o The next elements in preorder will correspond to the left and right subtrees in the
same manner.
Construction Code
Here’s a C implementation to construct the binary tree and perform postorder traversal:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char data;
struct Node* left;
struct Node* right;
};
return root;
}
int main() {
char inorder[] = "HKDBILEAFCMJG";
char preorder[] = "ABDHKELCFGJM";
int preorderIndex = 0;
return 0;
}
Explanation of the Code
1. Node Structure: A simple structure to represent a node in the binary tree.
2. Create Node: A function to allocate memory and initialize a new node.
3. Find Index: A function to find the index of a given value in the inorder array.
4. Build Tree: A recursive function that constructs the binary tree using the inorder and
preorder traversals. It finds the root, splits the inorder traversal for left and right subtrees,
and recursively builds the tree.
5. Postorder Traversal: A function to print the postorder traversal of the tree (left, right, root).
6. Main Function: Initializes the traversals, constructs the tree, and prints the postorder
traversal.
Output
When you run the above code, you will get the postorder traversal of the constructed binary tree:
mathematica
Postorder traversal: H K D E I L B F G J M C A
Explain B-Tree. Construct a B-Tree of order 4 with the alphabets (letters) arrive in the sequence as
follows: a g f b k d h m j e s i r x c l n t u p
4
Solution:
A B-Tree is a self-balancing tree data structure that maintains sorted data and allows for efficient
insertion, deletion, and search operations. It is designed to work well on disk storage systems and
databases, allowing for high levels of concurrency and minimal disk reads. Key characteristics of B-
Trees include:
1. Order: A B-Tree of order m can have a maximum of m - 1 keys and m children. Each node
(except the root) must contain at least ⌈m/2⌉ - 1 keys.
2. Sorted Keys: Keys in each node are kept in sorted order.
3. Balanced: All leaf nodes are at the same depth, ensuring that the tree remains balanced.
4. Multi-way: Unlike binary trees, B-Trees can have multiple children, allowing them to store
more keys in a single node.
Constructing a B-Tree of Order 4
Order 4 means each node can have at most 3 keys and 4 children. Let's construct a B-Tree using the
sequence of letters provided:
a, g, f, b, k, d, h, m, j, e, s, i, r, x, c, l, n, t, u, p.
[g]
/ \
[b h] [l]
/ | | \
[a c d e] [f] [i r] [k m n p s t u x]
5 Construct a tree for the given inorder and postorder traversals.
Inorder : D G B A H E I C F
Postorder : G D B H I E F C A
Solutions:
To construct a binary tree from given inorder and postorder traversals, we can follow a systematic
approach:
Given Traversals
• Inorder: D G B A H E I C F
• Postorder: G D B H I E F C A
Steps to Construct the Tree
1. Identify the Root: The last element of the postorder traversal is always the root of the tree. In
this case, the root is A.
2. Split Inorder Traversal: Find the index of the root (A) in the inorder traversal. This index will
help us split the inorder list into left and right subtrees:
o Left Subtree: Elements before A in inorder
o Right Subtree: Elements after A in inorder
For our case:
o Left Subtree (Inorder): D G B
o Right Subtree (Inorder): H E I C F
3. Recursive Construction: We recursively apply the same process for the left and right subtrees
using the remaining elements in the postorder list:
o The postorder elements corresponding to the left subtree will come from the postorder
list before the root.
Step-by-Step Construction
1. Identify the Root
• Root = A
2. Split Inorder and Postorder
• Inorder: D G B (left of A), H E I C F (right of A)
• Postorder: Last element is A, so remaining for left and right subtrees.
Left Subtree
• Postorder for Left Subtree: G D B
• Inorder for Left Subtree: D G B
• Root for left subtree is B.
• Inorder Split:
o Left: D
o Right: G
• Postorder for Left Subtree:
o Left: D
o Right: G
Right Subtree
• Postorder for Right Subtree: H I E F C
• Inorder for Right Subtree: H E I C F
• Root for right subtree is C.
• Inorder Split:
o Left: H E I
o Right: F
• Postorder for Right Subtree:
o Left: H I E
o Right: F
Recursively Constructing the Tree
1. For Left Subtree of A (Root B):
o Left of B: Root D (No children)
o Right of B: Root G (No children)
2. For Right Subtree of A (Root C):
o Left of C: Root E
▪ Left of E: Root H (No children)
▪ Right of E: Root I (No children)
o Right of C: Root F (No children)
Final Tree Structure
Now, let's put it all together. The final binary tree can be represented as:
mathematica
Copy code
A
/\
B C
/\ \
D G F
/
E
/\
H I
Implementation in C
Here's how you might implement this in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char data;
struct Node* left;
struct Node* right;
};
// Build the right and left subtrees (right first because we are using postorder)
root->right = buildTree(inorder, postorder, rootIndex + 1, inorderEnd, postIndex);
root->left = buildTree(inorder, postorder, inorderStart, rootIndex - 1, postIndex);
return root;
}
int main() {
char inorder[] = "DGBAEIHCF";
char postorder[] = "GDBHIEFC A";
int postIndex = strlen(postorder) - 1;
return 0;
}
6 Discuss following with reference to trees.
i Height of the tree
ii Complete Binary Tree
iii Extended Binary tree
iv Sibling
v Full Binary Tree
vi Complete Binary Tree
Solutions
(i) Height of the Tree
Definition: The height of a tree is defined as the length of the longest path from the root node to a
leaf node. It can be thought of as the number of edges on the longest downward path between the
root and a leaf.
Properties:
• For an empty tree, the height is -1.
• For a tree with only one node (the root), the height is 0.
• The height of a binary tree with n nodes can be at most n-1 (in case of a skewed tree) and at
least ⌊log₂(n)⌋ (in case of a balanced tree).
(ii) Complete Binary Tree
Definition: A complete binary tree is a type of binary tree in which every level, except possibly the
last, is completely filled, and all nodes are as far left as possible.
Properties:
• The last level may not be completely filled, but all nodes must be filled from left to right.
• A complete binary tree with h height has between 2^h and 2^(h+1) - 1 nodes.
• It can be efficiently represented using an array, where for any node at index i, the left child is
at 2i + 1, and the right child is at 2i + 2.
(iii) Extended Binary Tree
Definition: An extended binary tree is a binary tree that is modified by adding null links to represent
absent children, effectively making every node have either 0 or 2 children.
Properties:
• In an extended binary tree, each node either has two children or is a leaf node (having no
children).
• This representation can help in visualizing recursive algorithms and simplifies some operations
(like traversal).
(iv) Sibling
Definition: In the context of trees, siblings are nodes that share the same parent.
Properties:
• Sibling nodes can be at the same level and typically belong to the same subtree.
• Understanding sibling relationships is important for tree traversal algorithms and operations
such as balancing or restructuring the tree.
(v) Full Binary Tree
Definition: A full binary tree (also known as a proper or strict binary tree) is a type of binary tree in
which every node other than the leaves has exactly two children.
Properties:
• In a full binary tree, the number of leaf nodes is always one more than the number of internal
nodes.
• If a full binary tree has n internal nodes, then it has n + 1 leaf nodes.
• The height of a full binary tree with n internal nodes is log₂(n + 1).
(vi) Complete Binary Tree (repeated)
Definition: As previously defined, a complete binary tree is one in which all levels are fully filled
except possibly the last, which is filled from left to right.
Properties:
• It is distinct from a full binary tree, as a complete binary tree does not require all nodes to
have two children.
• Complete binary trees are often used in implementing heaps (binary heaps), as their structure
allows for efficient operations like insertion and deletion.
7. Write a short note on Threaded binary tree. Explain the significance of maintaining threads in Binary Search
Tree. Write an algorithm to insert a node in thread binary tree.
Solutions
Threaded Binary Tree
A threaded binary tree is a type of binary tree that makes use of the null pointers in the tree nodes
to point to their in-order predecessor and successor. This effectively creates a structure that allows
for efficient in-order traversal without the need for a stack or recursion.
Characteristics
• Threading: In a threaded binary tree, a null pointer in a node indicates that the node has a
predecessor or successor. If a node's left pointer is null, it points to its in-order predecessor; if
the right pointer is null, it points to its in-order successor.
• In-order Traversal: This structure allows for an easy in-order traversal. Instead of using a
stack or recursion, you can follow the threads to visit nodes in order.
• Storage Efficiency: By utilizing null pointers for threading, no additional space is needed for
storing references to predecessors and successors.
Significance of Maintaining Threads in Binary Search Trees (BST)
1. Efficient Traversal: Maintaining threads allows for in-order traversal of the tree in a linear
fashion without the overhead of a stack or recursive function calls.
2. Improved Performance: This can lead to improved performance in scenarios where frequent
traversals are required, such as in applications involving sorted data retrieval.
3. Reduced Memory Usage: It minimizes the memory footprint compared to storing additional
pointers or using stack-based traversal techniques.
Algorithm to Insert a Node in a Threaded Binary Tree
Here's a simple algorithm to insert a new node into a threaded binary tree:
1. Start at the root of the tree.
2. Use a loop to find the appropriate location for the new node based on binary search tree
properties (i.e., left children are less than the parent node, right children are greater).
3. When a null pointer is found, insert the new node:
o If it's the left null pointer, set it to point to the new node and adjust the new node's
right pointer to point to the current node (the successor).
o If it's the right null pointer, set it to point to the new node and adjust the new node's
left pointer to point to the current node (the predecessor).
4. Update the threaded links accordingly.
C Implementation of Node Insertion in a Threaded Binary Tree
Here's a simple implementation in C to demonstrate inserting a node in a threaded binary tree:
#include <stdio.h>
#include <stdlib.h>
struct ThreadedNode {
int data;
struct ThreadedNode *left, *right;
int leftThread, rightThread; // 1 if thread, 0 if child
};
if (newNode->left != NULL) {
// Update predecessor's right thread
struct ThreadedNode* predecessor = newNode->left;
predecessor->right = newNode;
}
} else {
newNode->right = parent->right;
newNode->left = parent;
parent->right = newNode;
parent->rightThread = 1;
if (newNode->right != NULL) {
// Update successor's left thread
struct ThreadedNode* successor = newNode->right;
successor->left = newNode;
}
}
}
// Main function
int main() {
struct ThreadedNode* root = NULL;
insertNode(&root, 10);
insertNode(&root, 5);
insertNode(&root, 20);
insertNode(&root, 3);
insertNode(&root, 7);
insertNode(&root, 15);
insertNode(&root, 30);
return 0;
}
8 Create a Binary Search Tree for the following data and do in-order, Preorder and Post-order traversal of
the tree: 50, 60, 25, 40, 30, 70, 35, 10, 55, 65, 5
Solution
To create a Binary Search Tree (BST) from the given data, we will insert the numbers one by one
while maintaining the properties of the BST. The numbers to be inserted are:
50, 60, 25, 40, 30, 70, 35, 10, 55, 65, 5
Step-by-Step Construction of the BST
1. Insert 50: This becomes the root.
50
2. Insert 60: This goes to the right of 50.
50
\
60
3. Insert 25: This goes to the left of 50.
50
/ \
25 60
4. Insert 40: This goes to the right of 25.
50
/ \
25 60
\
40
5. Insert 30: This goes to the left of 40.
50
/ \
25 60
\
40
/
30
6. Insert 70: This goes to the right of 60.
50
/ \
25 60
\ \
40 70
/
30
7. Insert 35: This goes to the right of 30.
50
/ \
25 60
\ \
40 70
/
30
\
35
8. Insert 10: This goes to the left of 25.
50
/ \
25 60
/ \ \
10 40 70 / 30
35
50
/ \
25 60
/\/
10 40 55 70 / 30
35
50
/ \
25 60
/\/
10 40 55 70 / / / 5 30 65
35
50
/ \
25 60
/\/
10 40 55 70 / / / 5 30 65
35
markdown
Copy code
### Traversals
Now, we will perform in-order, pre-order, and post-order traversals of the constructed BST.
- **In-Order**: `5, 10, 25, 30, 35, 40, 50, 55, 60, 65, 70`
- **Pre-Order**: `50, 25, 10, 5, 40, 30, 35, 60, 55, 70, 65`
- **Post-Order**: `5, 10, 35, 30, 40, 25, 55, 65, 70, 60, 50`
9 Write a C function for non-recursive post order traversal of a binary tree.
Solution.
To perform a non-recursive post-order traversal of a binary tree, we can use two stacks or a single
stack along with a pointer to keep track of the last visited node. Here, I’ll show you how to do it
using a single stack.
C Function for Non-Recursive Post-Order Traversal
Here's a complete C function to perform non-recursive post-order traversal:
#include <stdio.h>
#include <stdlib.h>
return 0;
}
Explanation of the Code
1. Node Structure: The Node structure defines a binary tree node with data and pointers to the
left and right children.
2. Create Node Function: createNode allocates memory for a new node and initializes its data
and pointers.
3. Post-Order Traversal Function:
o We use a stack to keep track of nodes.
o The outer loop continues until both the stack is empty and the root is NULL.
o The inner loop traverses down the leftmost path, pushing each node onto the stack.
o After reaching the leftmost node, we check the top of the stack:
▪ If the right child of the node at the top of the stack is NULL or already visited,
we visit that node (print its data) and pop it from the stack.
▪ If there is a right child that has not been visited, we set root to that right child
and continue.
4. Main Function: An example tree is created, and the post-order traversal is called.
Example Output
For the tree constructed in the example, the output will be:
Post-order traversal: 4 5 2 3 1
10 Define an AVL tree. Obtain an AVL tree by inserting one integer at a time in the following sequence. 150,
155, 160, 115, 110, 140, 120, 145, 130, 147, 170, 180. Show all the steps.
Solution
150
2. Insert 155
150
\
155
3. Insert 160
o Inserting 160 causes the tree to become unbalanced.
150
\
155
\
160
o Balance Factor: Node 150 has a balance factor of -2 (right-heavy).
o Rotation: Left Rotation on 150.
155
/ \
150 160
4. Insert 115
155
/ \
150 160
/
115
5. **Insert 110**
155
/ \
150 160
/ 115 / 110
155
/ \
115 160
/
110 150
6. **Insert 140**
155
/ \
115 160
/
110 150 / 140
7. **Insert 120**
155
/ \
115 160
/
110 150 /
140 120
- **Balance Factor**: Node `115` has a balance factor of `1`, Node `150` has a balance factor of
`1`, and Node `155` remains balanced.
8. **Insert 145**
155
/ \
115 160
/
110 150 /
140 120
145
9. **Insert 130**
155
/ \
115 160
/
110 150 /
140 120
145 / 130
- **Balance Factor**: Node `120` has a balance factor of `1`, Node `150` has a balance factor of
`1`, but Node `155` has a balance factor of `2` (right-heavy).
- **Rotation**: Right rotation on `150`, then left rotation on `155`.
140
/ \
115 155
/\/
110 120 150 160
145 / 130
140
/ \
115 155
/\/
110 120 150 160
145 / 130
147
140
/ \
115 155
/\/
110 120 150 160
145 / 130
147
170
140
/ \
115 155
/\/
110 120 150 160
145 / 130
147
170
180
140
/ \
115 155
/\/
110 120 150 170 /
160 180 / 145 / 130
147
After inserting all the integers, the final AVL tree looks like this:
140
/ \
115 155
/\/
110 120 150 170 /
160 180 / 145 / 130
147
11 Suppose character a, b, c, d, e, f has probabilities 0.07, 0.09, 0.12, 0.22, 0.23, 0.27 respectively. Find
an optional Huffman code and draw the Huffman tree. Also find the average code length.
Solution.
to find an optimal Huffman code for the given set of characters and their probabilities, we need to
follow these steps:
1. List the characters and their probabilities:
• Character a: 0.07
• Character b: 0.09
• Character c: 0.12
• Character d: 0.22
• Character e: 0.23
• Character f: 0.27
2. Create a Priority Queue (Min-Heap) to start building the Huffman tree:
The priority queue stores characters based on their probabilities, starting with the smallest.
Step 1: Insert each character with its corresponding probability into the priority queue:
• a: 0.07
• b: 0.09
• c: 0.12
• d: 0.22
• e: 0.23
• f: 0.27
Step 2: Merge the two nodes with the lowest probabilities.
• Merge a (0.07) and b (0.09) → new node with probability 0.16.
o New heap: [(0.12, c), (0.16, ab), (0.22, d), (0.23, e), (0.27, f)]
Step 3: Merge the next two lowest probabilities.
• Merge c (0.12) and ab (0.16) → new node with probability 0.28.
o New heap: [(0.22, d), (0.23, e), (0.27, f), (0.28, abc)]
Step 4: Merge the next two lowest probabilities.
• Merge d (0.22) and e (0.23) → new node with probability 0.45.
o New heap: [(0.27, f), (0.28, abc), (0.45, de)]
Step 5: Merge the next two lowest probabilities.
• Merge f (0.27) and abc (0.28) → new node with probability 0.55.
o New heap: [(0.45, de), (0.55, fabc)]
Step 6: Merge the remaining two nodes.
• Merge de (0.45) and fabc (0.55) → new node with probability 1.00 (root of the tree).
o New heap: [(1.00, root)]
At this point, the heap has only one node, which means we've finished constructing the Huffman
tree.
3. Huffman Tree Structure:
• Root (1.00)
o Left child: de (0.45)
▪ Left child: d (0.22)
▪ Right child: e (0.23)
o Right child: fabc (0.55)
▪ Left child: f (0.27)
▪ Right child: abc (0.28)
▪ Left child: a (0.07)
▪ Right child: b (0.09)
▪ Right child: c (0.12)
4. Assigning Huffman Codes:
Starting from the root, assign a "0" for left branches and a "1" for right branches:
• f: 01
• a: 100
• b: 101
• c: 11
• d: 00
• e: 01
5. Average Code Length Calculation:
The average code length is the weighted average length of the Huffman codes, calculated as follows:
Average Code Length=∑(Probability of Character×Length of Huffman Code for Character)
To show that the external path length (E) of a binary tree is related to the internal path length (I)
by the formula:
E=I+2n
where n is the number of internal nodes, we need to carefully define and understand the concepts of
internal and external path lengths in the context of binary trees.
Definitions:
1. Internal Path Length (I): The sum of the depths of all internal nodes in the binary tree. The
depth of a node is defined as the number of edges on the path from the root to the node.
o If a node is at depth d, then the contribution of that node to the internal path length is
d.
2. External Path Length (E): The sum of the depths of all external nodes (or leaf nodes) in the
binary tree. External nodes are the nodes that would be reached if we kept following left or
right child pointers in an empty subtree (i.e., the "holes" or "ends" of the tree).
o The contribution of each external node is its depth in the tree.
3. Number of Internal Nodes (n): This is the total number of nodes in the tree that are not
external (leaf) nodes.
Proof:
Step 1: Relation between External and Internal Nodes
In a binary tree, each internal node has exactly 2 children (since it's a full binary tree). Thus, for
every internal node, there are two child nodes, which are either internal or external nodes. The
number of external nodes m in a binary tree with n internal nodes can be shown to be:
m=n+1
This result follows from the fact that in a full binary tree, the number of external nodes is always
one more than the number of internal nodes. This is a key property of binary trees.
Step 2: Total Path Length Calculation
Let’s now compute the total path length (the sum of the depths of all nodes) in the binary tree. This
includes both the internal path length I and the external path length E.
The total path length is the sum of the depths of all internal and external nodes:
Total Path Length=I+E
However, there's another important property of binary trees that we can use. If the tree has nnn
internal nodes, then the total number of nodes in the tree is n+m=2n+1 (internal plus external
nodes). The depth of each node is counted in terms of the number of edges from the root to that
node.
Step 3: The Depth of Internal and External Nodes
Consider the following observations:
• The total path length for internal nodes I can be computed as the sum of their depths.
• The total path length for external nodes E can similarly be computed as the sum of their
depths.
There’s a relationship between the total depth of internal nodes and the total depth of external
nodes. Specifically, when we look at the total depth of all nodes in the tree (internal and external),
it can be shown that:
Solution
In a Binary Search Tree (BST), the search operation works by comparing the key at the current node
with the desired key, and recursively searching either the left or the right subtree based on the
comparison. The time complexity for searching in a BST is:
• O(h), where h is the height of the tree.
• In the worst case, the tree could be highly unbalanced, where the height is O(n), and thus the
search time could be O(n), which is inefficient.
In contrast, a B-tree is a self-balancing tree data structure that ensures balanced height by
maintaining nodes with multiple keys and children. The search operation in a B-tree works by
traversing the tree from the root to the appropriate leaf node, following the child pointers.
• B-tree height is much smaller compared to a BST because each node can have many children
(up to the order of the tree). The height of a B-tree is O(log_d n), where d is the order of the
tree, and n is the number of keys stored in the tree.
o This means that the number of levels you need to traverse in a B-tree is much smaller
than in a binary tree.
Thus, a B-tree can offer better search time in comparison to a BST because:
1. The height of a B-tree grows logarithmically, while a BST can degrade to linear height.
2. In each node of a B-tree, you perform a binary search over multiple keys, reducing the
number of node accesses.
B-Tree Insertion and Deletion
Now, let’s proceed with the insertion of the keys into a B-tree of order 5 and then delete the keys j,
t, and d.
Definitions:
• B-tree of order 5: This means each node can have at most 4 keys and at most 5 children
(since the order is 5).
• The tree must remain balanced, meaning all leaf nodes must be at the same level.
Insert Keys into B-tree of Order 5
We are given the keys: a, g, f, b, k, d, h, m, j, e, s, i, r, x, c, l, n, t, u, p.
Let’s go through the insertion steps one by one:
Step-by-Step Insertion:
1. Insert a:
The tree is empty. Insert a into the root.
Tree: [a]
2. Insert g:
Insert g into the root, which already has one key.
Tree: [a, g]
3. Insert f:
Insert f. The keys in the root node are now [a, f, g]. The tree is still valid.
Tree: [a, f, g]
4. Insert b:
Insert b. The keys in the root are now [a, b, f, g]. The tree is still valid.
Tree: [a, b, f, g]
5. Insert k:
The root has 4 keys. We need to split it. Split the node into two:
o Middle key: f (this will become the new root).
o Left child: [a, b].
o Right child: [g, k].
Tree:
[f]
/ \
[a, b] [g, k]
6. **Insert d**:
Insert **d** into the left child **[a, b]**.
Tree:
[f]
/ \
[a, b, d] [g, k]
7. **Insert h**:
Insert **h** into the right child **[g, k]**.
Tree:
[f]
/ \
[a, b, d] [g, h, k]
8. **Insert m**:
Insert **m** into the right child **[g, h, k]**. The node now has 4 keys, so we split it:
- **Middle key**: **h** (this will be pushed up into the root).
- Left child: **[g]**.
- Right child: **[k, m]**.
Tree:
[f, h]
/ | \
[a, b, d] [g] [k, m]
9. **Insert j**:
Insert **j** into the right child **[k, m]**.
Tree:
[f, h]
/ | \
[a, b, d] [g] [j, k, m]
less
- **Characteristics:**
- Every node (except the leaf node) has only a left child.
- The height of the tree is equal to the number of nodes, i.e., the tree has **n - 1** height, where
**n** is the number of nodes.
- In such a tree, the time complexity for searching, inserting, and deleting elements becomes
**O(n)**, which is inefficient.
A **right-skewed binary tree** is the opposite of the left-skewed tree. In a right-skewed tree, every
node has only a right child and no left child. This also leads to a structure that resembles a linked
list but with all nodes "leaning" to the right.
- **Example Structure:**
10
\
9
\
8
\
7
- **Characteristics:**
- Every node (except the leaf node) has only a right child.
- The height of the tree is also equal to **n - 1**.
- The time complexity for search, insert, and delete operations becomes **O(n)**, leading to
inefficient performance.
In both cases, the height of the tree increases linearly with the number of nodes, resulting in
inefficient operations. This is why **balanced** binary trees, such as **AVL trees** or **Red-Black
trees**, are preferred for efficient searching, inserting, and deleting.
---
An **AVL tree** is a **self-balancing binary search tree** where the difference between the heights of
the left and right subtrees of every node (called the **balance factor**) is at most 1. If this balance
factor becomes greater than 1 or less than -1 at any node, the tree is rebalanced using **rotations**
(either **left** or **right** rotations).
We are given the following elements for insertion in an AVL tree: **60, 2, 14, 22, 13, 111, 92, 86**.
Let's go step by step to insert these elements while maintaining the AVL property.
- **Balance check**: The balance factor of 60 is **+1** (left subtree height = 1, right subtree height =
0), which is within the allowed range of -1, 0, +1. So, the tree is balanced.
- **Balance check**: The balance factor of 2 is **-1** (left subtree height = 0, right subtree height =
1). The balance factor of 60 is **+2**, which indicates the tree is unbalanced at node 60. To restore
balance, we perform a **left rotation** on node 60.
- **Balance check**: The balance factor of node 14 is **0** (left and right subtrees are balanced). The
tree is still balanced.
- **Balance check**: The balance factor of node 14 becomes **+1** (left subtree height = 1, right
subtree height = 2). This balance factor is within the allowed range, so the tree remains balanced.
- **Balance check**: The balance factor of node 60 is **-1** (left subtree height = 0, right subtree
height = 2). The tree is still balanced.
- **Balance check**: The balance factor of node 111 is **+1** (left subtree height = 1, right subtree
height = 0). The balance factor of node 60 is **-1**, and the tree is balanced.
- **Balance check**: The balance factor of node 92 becomes **-1**, which is acceptable. The balance
factor of node 60 is **-2**, indicating an imbalance. To restore balance, we perform a **left
rotation** on node 111.
2
\
14
/ \
13 60
\ \
22 92
/ \
86 111
Solution.
To determine the minimum size of the array X required to store a binary tree with n vertices
(nodes), let's carefully analyse the indexing scheme given:
Given Scheme:
• Indexing starts at 1 (instead of 0).
• The root of the binary tree is stored at X[1].
• For a node stored at X[i]:
o The left child (if any) is stored at X[2i].
o The right child (if any) is stored at X[2i + 1].
Important Observations:
1. Array Structure:
o The array stores nodes in a specific pattern. For example:
▪ X[1] is the root node.
▪ X[2] is the left child of the root.
▪ X[3] is the right child of the root.
▪ X[4] is the left child of X[2], and so on.
o This indexing follows the structure of a complete binary tree where each node is
placed in a level-order manner.
2. Maximum Index:
o For any binary tree with n nodes, the last node (the n-th node) will be stored at index
n. The array must be large enough to accommodate up to this n-th node.
o The array indexing starts at 1 and goes up to n (the total number of nodes).
3. No Need for Extra Space:
o The structure of the binary tree ensures that the array can represent the tree correctly
by indexing each node and its children as described. Even if the tree is sparse, the
array will not require more than n elements because:
▪ The leaf nodes and internal nodes are indexed consecutively.
▪ There is no wasted space in the array, and you don’t need to reserve extra
positions for non-existent children of leaf nodes.
Conclusion:
• The minimum size of the array X must be exactly n to store a binary tree with n vertices
(since the array is indexed starting from 1 and can store up to the n-th node).
Thus, the minimum size of the array X to store any binary tree with n vertices is n.
Answer:
The minimum size of the array X to store a binary tree with n nodes is n.
19 Write the various properties of B- Tree. Show the results of inserting the keys F, S, Q, K, C, L, H, T, V, W, M,
R, N, P, A, B in order into an empty B-Tree of order 5.
Solution.
Properties of B-Trees:
A B-tree is a self-balancing search tree in which nodes can have multiple keys and children. It is
commonly used in databases and file systems because it allows for efficient insertion, deletion, and
search operations. The B-tree properties are designed to keep the tree balanced and minimize the
number of disk accesses.
Here are the key properties of a B-tree of order m:
1. Order:
o The order mmm of a B-tree defines the maximum number of children each node can
have. A B-tree of order mmm has the following properties:
▪ Each node can have at most m children.
▪ Each node can have at most m−1 keys.
▪ Each internal node (non-leaf node) has at least ⌈m/2⌉ children, except for the
root, which can have fewer than this minimum.
2. Root Node:
o The root node must have at least one child if it is not a leaf node.
o If the root is a leaf, it may contain fewer than ⌈m/2⌉ keys.
3. Leaf Nodes:
o Leaf nodes do not have children. They must contain between ⌈m/2⌉−1 keys.
4. Balanced Tree:
o All leaf nodes are at the same level, ensuring the tree is balanced.
o This property ensures that the height of the tree is logarithmic with respect to the
number of keys, leading to efficient search, insert, and delete operations.
5. Insertion:
o Insertion in a B-tree maintains its properties, and if a node overflows (i.e., has more
than m−1keys), the node splits into two nodes, and the middle key is promoted to the
parent node.
6. Deletion:
o Deletion involves removing a key from a leaf or internal node and ensuring that the tree
remains balanced. If a node becomes underfull (i.e., it has fewer than ⌈m/2⌉−1 keys), it
may borrow a key from a sibling or merge with a sibling.