Advanced Data Structures - Notes
Advanced Data Structures - Notes
UNIT I: Introduction to Data Structures, Singly Linked Lists, Doubly Linked Lists, Circular Lists
Algorithms. Stacks and Queues: Algorithm Implementation using Linked Lists.
UNIT II: Searching-Linear and Binary, Search Methods, Sorting-Bubble Sort, Selection Sort,
Insertion
Sort, Quick Sort, Merge Sort. Trees- Binary trees, Properties, Representation and Traversals (DFT,
BFT),
Expression Trees (Infix, prefix, postfix). Graphs-Basic Concepts, Storage structures and Traversals.
UNIT III: Dictionaries, ADT, The List ADT, Stack ADT, Queue ADT, Hash Table Representation,
Hash Functions, Collision Resolution-Separate Chaining, Open Addressing-Linear Probing, Double
Hashing.
UNIT IV: Priority queues- Definition, ADT, Realizing a Priority Queue Using Heaps, Definition,
Insertion, Deletion .Search Trees- Binary Search Trees, Definition, ADT, Implementation, Operations
UNIT V: Search Trees- AVL Trees, Definition, Height of AVL Tree, Operations-, Insertion, Deletion
and Searching, Introduction to Red-Black and Splay Trees, B-Trees, Height of B-Tree, Insertion,
Deletion
Previous paper:
UNIT-I
1. a With neat diagrams, explain the following operations in Singly Linked List data
structure.
i) Insert element at the end
ii) Delete the specified element
b. Write an algorithm for Push and Pop operations of Stack and list out its applications.
OR
2.a.Which operation is more efficient in Doubly Linked List over Singly Linked List?
b Explain in detail the list of operations that can be performed on a Circular Linked Lists with
appropriate diagrams.
UNIT-II
3. a Write the Insertion sort algorithm and explain the step by step procedure of Insertion
Sort method for sorting the following unordered list of elements 25,67,56,32,12,96,82,44.
Trace the steps to search for the element 82 using Binary search.
b Write the BFS algorithm and derive its complexity.
OR
4.a Write and explain the Quick sort algorithm and derive its best, worst and average case
time complexities.
b Briefly discuss various Tree traversal techniques.
UNIT-III
5. a Explain the operations of List ADT. And also specify their applications in real time.
b. What is meant by Hashing in data structure? Why do we need Hashing? Explain about
various types of Hash functions.
OR
6.a Explain the operations of Queue ADT. And also specify their applications in real
b Explain Double Hashing with an example.
UNIT - 4
7.a Explain the implementation of Priority Queue with an example.
b. Explain the delete and search operations in a Binary Search Tree with examples.
OR
8.a Write the properties of Binary Search Trees.
b. Explain the construction of a Binary Search Tree by inserting the elements 13, 3, 4, 12, 14,
10, 5, 1, 8, 2, 7, 9, 11, 6, 18 in the same order, starting from an empty tree.
UNIT-V
9. a Explain how the AVL tree insertion process makes it balanced through various rotations.
b. Explain the properties of Red-Black trees with a neat diagram and discuss its advantages.
OR
10. Construct a B-tree of order 4 for the following list of elements.
1,4, 7, 10, 17, 21, 31, 25, 19, 20, 28, 42
i) Assume the initial B- tree is empty. ii) Insertion should take place in the given order
iii) Show the tree after deleting the three elements 28, 31, 21, 25, and 19 in
sequence.
Answers :
1. Insert Element at the End: Known as "Insertion at Tail." This requires traversing the entire list to find
the last node and then adding the new node after this. The new node's next pointer is set to null,
indicating the end of the list. Since you need to traverse the entire list, this operation has a time
complexity of O(n), where n is the number of nodes in the list.
Steps:
o Allocate memory for the new node and assign the data to it.
o If head == NULL, make the new node the head of the list.
o Start from the head and follow the next pointers until you reach the last node (node->next ==
NULL).
o Set the next pointer of the last node to point to the new node.
Diagram:
Copy code
Insert 40:
Pseudocode:
java
newNode.next = null;
if (head == null) {
2. Delete the Specified Element : To delete a node after a specific node, you update the next pointer
of the preceding node to skip the node to be deleted and point to the following node. Depending on
the position of the node to delete, this can also involve traversing the list, making it O(n).
Steps:
Diagram:
Initial List: [10] -> [20] -> [30] -> NULL
Delete 20:
[10] -> [30] -> NULL
Pseudocode:
if (head == null) {
if (head.data == target) {
return head.next;
prev = current;
current = current.next; // Traverse the list
if (current != null) {
return head;
A Stack is a linear data structure that holds a linear, ordered sequence of elements. It is an abstract
data type. A Stack works on the LIFO process (Last In First Out), i.e., the element that was inserted
last will be removed first. To implement the Stack, it is required to maintain a pointer to the top of
the Stack, which is the last element to be inserted because we can access the elements only on the
top of the Stack.
Operation on Stack :
1. PUSH: PUSH operation implies the insertion of a new element into a Stack. A new element is
always inserted from the topmost position of the Stack; thus, we always need to check if the top is
empty or not, i.e., TOP=Max-1 if this condition goes false, it means the Stack is full, and no more
elements can be inserted, and even if we try to insert the element, a Stack overflow message will be
displayed.
Algorithm:
Step-1: If TOP = Max-1
Print “Overflow”
Goto Step 4
Step-4: END
2. POP: POP means to delete an element from the Stack. Before deleting an element, make sure to
check if the Stack Top is NULL, i.e., TOP=NULL. If this condition goes true, it means the Stack is empty,
and no deletion operation can be performed, and even if we try to delete, then the Stack underflow
message will be generated.
Algorithm:
Print “Underflow”
Goto Step 4
Step-4: END
1. A Stack can be used for evaluating expressions consisting of operands and operators.
2. Stacks can be used for Backtracking, i.e., to check parenthesis matching in an expression.
OR
Applications of Stack
2. Function Call Management: Tracks active functions and their states in recursion.
4. Backtracking: Helps in solving problems like maze navigation or the N-Queens problem.
Doubly linked lists are more efficient than singly linked lists in the following cases:
In Bi-directional Traversals:
Doubly linked lists allow for traversal in both the forward and backward directions, while
singly linked lists only allow for forward traversal.
This can be useful for applications where it is necessary to traverse the list in both directions,
such as a web browser's history list or a music player's playlist.
Since Doubly Linked Lists have two pointers for each node, it is possible to delete a node of
the list without having to traverse the entire list.
This can be significantly faster than deleting an element in a singly linked list, which requires
traversing the list from the beginning until the element is found because we need previous
pointer to reconnect the singly linked list.
Doubly linked lists are more efficient than singly linked lists in this case because they have
two pointers for each node, one to the next node and one to the previous node, and we
don't need to traverse the linked list now .
This allows for direct access of node and its adjacent nodes, which means that this operation
can be performed in O(1) time, regardless of the length of the list.
Doubly linked lists can be used to implement stacks and queues very efficiently. In fact,
doubly linked lists are the preferred data structure for implementing these data structures in
many programming languages.
o Deque Operations: Doubly linked lists are used in implementing deque (double-
ended queue) data structures efficiently. Deque supports insertion and deletion from
both ends in constant time with a doubly linked list. This makes operations like
enqueue and dequeue in a queue or push and pop in a stack more efficient when
implemented using a doubly linked list.
o Memory Allocation and Deallocation: Doubly linked lists can be helpful in memory
management scenarios where you need to allocate and deallocate memory blocks
dynamically. When deallocating memory blocks, if you have a reference to a node in
a doubly linked list, you can remove it in constant time, making memory deallocation
more efficient compared to singly linked lists.
o Undo Operations: Doubly linked lists are useful for implementing undo functionality
in applications. Each operation can be stored as a node, and moving backward
(undo) or forward (redo) in the history is efficient with the bidirectional pointers in a
doubly linked list.
Conclusion:
Doubly linked lists are more efficient than singly linked lists in terms of performance, but they
also require more memory. Doubly linked lists are often used in applications where performance
is a critical concern, such as web browsers, operating systems, and databases. However, they are
not as widely used as singly linked lists, which are simpler to implement and require less
memory. The best choice for a particular application will depend on the specific requirements of
that application.
2b.
A Circular Linked List (CLL) is a variation of a linked list where the last node points back to the
first node, forming a circle. This structure can be used with either singly linked or doubly linked
lists.
Here’s an explanation of the operations that can be performed on a Circular Linked List:
1. Traversal
Keep visiting the next node until you return to the head.
Algorithm:
2. Do:
Move to current.next.
2. Insertion
1. At the Beginning:
2. At the End:
o Insert the new node after the last node.
o Update the next pointer of the last node to the new node.
3. At a Specific Position:
o Insert the new node by adjusting the next pointers of the surrounding nodes.
3. Deletion
o Traverse the list to find the node just before the one to be deleted.
4. Searching
If you reach head again without finding the value, it is not present.
Each node has a data field and a next pointer. The last node’s next points to the head.
3a.
Insertion Sort Algorithm
Insertion Sort is a comparison-based sorting algorithm that builds the sorted list one element at a
time by inserting each new element into its correct position in the already sorted portion.
Step-by-Step Procedure
1. Initial list: [25, 67, 56, 32, 12, 96, 82, 44]
3. Pass 2: Compare 56 with 67 and 25. Shift 67 to the right and insert 56.
Result: [25, 56, 67, 32, 12, 96, 82, 44]
4. Pass 3: Compare 32 with 67, 56, and 25. Shift 67 and 56 to the right and insert 32.
Result: [25, 32, 56, 67, 12, 96, 82, 44]
5. Pass 4: Compare 12 with 67, 56, 32, and 25. Shift all to the right and insert 12.
Result: [12, 25, 32, 56, 67, 96, 82, 44]
7. Pass 6: Compare 82 with 96. Shift 96 to the right and insert 82.
Result: [12, 25, 32, 56, 67, 82, 96, 44]
8. Pass 7: Compare 44 with 96, 82, 67, 56, 32, and 25. Shift appropriate elements to the right
and insert 44.
Result: [12, 25, 32, 44, 56, 67, 82, 96]
2. Repeat until low > high: 2.1. Calculate mid = (low + high) // 2.
2.2. Compare A[mid] with the target: - If A[mid] == target, return mid (element found).
- If A[mid] < target, set low = mid + 1 (search right).
- If A[mid] > target, set high = mid - 1 (search left).
Sorted list: [12, 25, 32, 44, 56, 67, 82, 96]
3b.
Breadth-first Search (BFS) is a graph traversal algorithm that explores all the vertices of a graph in
a breadthwise order. It means it starts at a given vertex or node and visits all the vertices at the same
level before moving to the next level. It is a recursive algorithm for searching all the vertices of a
graph or tree data structure.
BFS Algorithm
For the BFS implementation, we will categorize each vertex of the graph into two categories:
1. Visited
2. Not Visited
Algorithm :
1. Start by selecting a starting vertex or node.
2. Add the starting vertex to the end of the queue.
3. Mark the starting vertex as visited and add it to the visited array/list.
4. While the queue is not empty, do the following steps:
o Remove the front vertex from the queue.
o Visit the removed vertex and process it.
o Enqueue all the adjacent vertices of the removed vertex that have not been
visited yet.
o Mark each visited adjacent vertex as visited and add it to the visited array/list.
5. Repeat step 4 until the queue is empty.
The space complexity of the breadth-first search algorithm : You can define the space complexity as
O(|V|), where |V| is the number of vertices in the graph, and different data structures are needed to
determine which vertices have already been added to the queue. This is also the space necessary for
the graph, which varies depending on the graph representation used by the algorithm's
implementation.
4a.
Quick Sort Algorithm
Partition Function
The partition function rearranges the array and determines the position of the pivot.
4. Finally, place the pivot in its correct position by swapping it with A[i+1]A[i+1]A[i+1].
o Occurs when the pivot divides the array into two nearly equal halves at each step.
o The recursion depth is logn\log nlogn, and at each level, O(n)O(n)O(n) work is done
for partitioning.
o The recursion depth becomes nnn, and partitioning at each level takes O(n)O(n)O(n).
o For a random pivot, the partitioning generally produces sub-arrays of roughly equal
size.
o The expected recursion depth is logn\log nlogn, and the total time is O(nlogn)O(n \
log n)O(nlogn).
Space Complexity
In the best and average cases: O(logn)O(\log n)O(logn), due to balanced recursion.
Summary of Complexities
4b.
Tree traversal is a process of visiting (reading or updating) each node in a tree data structure in a
specific order. The traversal techniques can be classified into two main types: Depth-First Traversal
(DFT) and Breadth-First Traversal (BFT).
This involves exploring as far as possible along a branch before backtracking. It includes the following
methods:
Use Case: Used in binary search trees (BSTs) to retrieve elements in sorted order.
Use Case: Used to create a copy of the tree or to prefix mathematical expressions.
This involves visiting all the nodes at one level before moving to the next level. It is typically
implemented using a queue.
a. Level-Order Traversal
Visit nodes level by level from top to bottom and left to right.
Use Case: Used in shortest path algorithms, such as BFS in graph theory.
Key Differences
5a.
Operations of List ADT
The List Abstract Data Type (ADT) represents a collection of ordered elements, where the same
element may occur multiple times. It supports various operations for manipulating the collection.
1. Insertion
2. Deletion
3. Traversal
o Finds and returns the position of a specific element if it exists in the list.
5. Access/Update
6. Concatenation
7. Sorting
8. Length/Size
1. Task Scheduling
o Used to maintain a list of tasks in project management tools like Trello or Asana.
2. Playlist Management
3. Text Editing
o Handles a sequence of characters or words in a text editor, where users can insert,
delete, or modify content.
5. Navigation Systems
6. Event Handling
7. Databases
9. Inventory Management
5b.
What is Hashing in Data Structures?
Hashing is a technique used in data structures to map data (keys) to a fixed-size table (hash table)
using a hash function. The goal of hashing is to enable fast data retrieval, insertion, and deletion
operations, often in constant time O(1)O(1)O(1).
1. Fast Access: Hashing provides efficient access to data compared to linear or binary search.
2. Memory Optimization: A hash table uses a fixed-size array, avoiding excessive memory
usage.
3. Collision Handling: Hashing allows multiple values to share the same index in the table and
resolves these collisions efficiently.
A hash function maps a given key to an index in the hash table. A good hash function minimizes
collisions and distributes keys uniformly across the table.
Computes the index as the remainder of the division of the key by the table size.
h(key)=keymod tableSizeh(key) = key \mod tableSizeh(key)=keymodtableSize
Example: If the key is 505050 and the table size is 777, h(50)=50mod 7=1h(50) = 50 \mod 7 =
1h(50)=50mod7=1.
2. Multiplication Method
Uses a constant AAA (where 0<A<10 < A < 10<A<1) and computes the index as:
h(key)=⌊tableSize⋅(key⋅Amod 1)⌋h(key) = \lfloor tableSize \cdot (key \cdot A \mod 1) \
rfloorh(key)=⌊tableSize⋅(key⋅Amod1)⌋
3. Mid-Square Method
Squares the key and extracts a portion of the digits from the middle to compute the index.
Divides the key into equal parts, adds them together, and computes the index using modulo
operation.
5. Universal Hashing
Uses a randomization approach to reduce collisions. A random hash function is selected from
a family of functions at runtime.
6. String Hashing
Converts strings into numerical values and hashes them using one of the above methods.
Common Techniques:
o Polynomial Hashing:
h(s)=(s[0]⋅p0+s[1]⋅p1+...+s[n−1]⋅pn−1)mod tableSizeh(s) = (s[0] \cdot p^0 + s[1] \
cdot p^1 + ... + s[n-1] \cdot p^{n-1}) \mod tableSizeh(s)=(s[0]⋅p0+s[1]⋅p1+...
+s[n−1]⋅pn−1)modtableSize, where ppp is a prime number.
7. Cryptographic Hashing
Uses secure hash functions like MD5, SHA-1, or SHA-256 for sensitive applications like
password storage and digital signatures.
6a. The queue in the data structure acts the same as the movie ticket counter. Both the ends of this
abstract data structure remain open. Further, the insertion and deletion processes also operate
analogously to the wait-up line for tickets.
Basic Operations for Queue in Data Structure :
Enqueue() - Insertion of elements to the queue.
Peek() - Acquires the data element available at the front node of the queue without deleting it.
Enqueue() Operation
Step 3: If the queue is not full, increment the rear pointer to point to the next available
empty space.
Step 4: Add the data element to the queue location where the rear is pointing.
Dequeue() Operation
Step 3: If the queue is not empty, access the data where the front pointer is pointing.
Step 4: Increment front pointer to point to the next available data element.
Step 5: Here, you have removed 7, 2, and -9 from the queue data str
Peek() Operation
Step 3: If the queue is not empty, access the data where the front pointer is pointing.
isFull() Operation
isNull() Operation
Step 1: Check if the rear and front are pointing to null memory space, i.e., -1.
Applications of Queue
Queue, as the name suggests, is utilized when you need to regulate a group of
objects in order. This data structure caters to the need for First Come First Serve
problems in different software applications. The scenarios mentioned below are a
few systems that use the queue data structure to serve their needs –
Printers: Queue data structure is used in printers to maintain the order of pages
while printing.
Interrupt handling in computes: The interrupts are operated in the same order as
they arrive, i.e., interrupt which comes first, will be dealt with first.
Switches and Routers: Both switch and router interfaces maintain ingress
(inbound) and egress (outbound) queues to store packets.
Customer service systems: It develops call center phone systems using the
concepts of queues.
6b.
Info about double hashing
7a. What is Priority Queue?
A priority queue is a type of data structure where each element has a priority assigned to it. Elements are processed based
on their priority, with higher priority elements being processed before lower priority ones. This is different from a regular
queue where elements are processed in the order they arrive (first-in, first-out).
A common application of priority queue data structure is task scheduling, where tasks with higher priority need to be
executed before others. They are also used in graph algorithms like Dijkstra's shortest path algorithm, where nodes with the
lowest cost are processed first.
import java.util.ArrayList;
public class PriorityQueue {
private ArrayList<Integer> heap;
public PriorityQueue() {
heap = new ArrayList<>();
}
private void heapifyUp(int index) {
int parentIndex = (index - 1) / 2;
if (index > 0 && heap.get(index) < heap.get(parentIndex)) {
int temp = heap.get(index);
heap.set(index, heap.get(parentIndex));
heap.set(parentIndex, temp);
heapifyUp(parentIndex);
}
}
private void heapifyDown(int index) {
int leftChildIndex = 2 * index + 1;
int rightChildIndex = 2 * index + 2;
int smallest = index;
if (leftChildIndex < heap.size() && heap.get(leftChildIndex) < heap.get(smallest)) {
smallest = leftChildIndex;
}
if (rightChildIndex < heap.size() && heap.get(rightChildIndex) < heap.get(smallest)) {
smallest = rightChildIndex;
}
if (smallest != index) {
int temp = heap.get(index);
heap.set(index, heap.get(smallest));
heap.set(smallest, temp);
heapifyDown(smallest);
}
}
public void insert(int element) {
heap.add(element);
heapifyUp(heap.size() - 1);
}
public int remove() {
if (heap.size() == 0) {
return -1;
}
if (heap.size() == 1) {
return heap.remove(0);
}
int root = heap.get(0);
heap.set(0, heap.remove(heap.size() - 1));
heapifyDown(0);
return root;
}
public int peek() {
if (heap.size() == 0) {
return -1;
}
return heap.get(0);
}
public boolean isEmpty() {
return heap.size() == 0;
}
public static void main(String[] args) {
PriorityQueue pq = new PriorityQueue();
pq.insert(10);
pq.insert(5);
pq.insert(20);
System.out.println(pq.remove()); // Output: 5
System.out.println(pq.peek()); // Output: 10
System.out.println(pq.isEmpty()); // Output: false
}
}
7b. A binary search tree (BST) in Data Structures is a sorted binary tree, where we can
easily search for any key using the binary search algorithm. We already have learned binary
search, tree data structure, and binary tree. In this DSA tutorial, we will learn binary search trees,
their operations, implementation, etc. To further enhance your understanding, consider enrolling in
the best DSA training, to gain comprehensive insights into effective data structure utilization for
improved problem-solving and time management.
1. The keys of nodes in the left subtree of a node are less than the node’s key.
2. The keys of nodes in the right subtree of a node are greater than the node’s key.
3. Both subtrees of each node are also BSTs i.e. they have the above two features.
1. Search
To search in a binary search tree, we need to take care that each left subtree has values below the
root and each right subtree has values above the root. If the value is below the root, the value is not
in the right subtree; we need to only search in the left subtree and if the value is above the root, the
value is not in the left subtree; we need to only search in the right subtree
2. If the root node is null, the tree is empty, and the search is unsuccessful.
3. If the search value is equal to the value of the current node, return the current node.
4. If the search value is less than the value of the current node, go to the left child node.
5. If the search value is greater than the value of the current node, go to the right child node.
6. Repeat steps 3 to 5 until the search value is found or the current node is null.
8. If root == NULL
9. return NULL;
10. If number == root->data
11. return root->data;
12. If number < root->data
13. return search(root->left)
14. If number > root->data
15. return search(root->right)
f the value is found, we return the value so that it gets propagated in each recursion step as shown in the image below. If
you might have noticed, we have called return search(struct node*) four times. When we return either the new node or
NULL, the value gets returned again and again until the search(root) returns the final result.
3. Deletion
To delete an element from a BST, the user first searches for the element using the search operation. If the element is found,
there are three cases to consider:
1.The node to be deleted has no children: In this case, simply remove the node from the tree.
2.The node to be deleted has only one child: In this case, remove the child node from its original position and replace the
node to be deleted with its child node.
3.The node to be deleted has two children: In this case, get the in-order successor of that node, replace the node with the
inorder successor, and then remove the inorder successor from its original position.
1. Time Complexity
Operations
Insertion O(log Space
n) Complexity
O(log n) O(n)
Insertion
Deletion O(log O(n)
n) O(log n) O(n)
Deletion
Search O(log O(n)
n) O(log n) O(n)
Search O(n)
8a.
Binary Search Tree Properties
A Binary Search Tree (BST) has specific properties that make it efficient for search, insertion, and
deletion operations:
1. Node Structure
2. Binary Tree
A BST in data structure is a type of binary tree, which means each node can have at most two
children: left and right.
3. Ordered Nodes
Left Subtree: For any given node, all the values in its left subtree are smaller than the value
of the node.
Right Subtree: For any given node, all the values in its right subtree are greater than the
value of the node.
Example:
The left child of 10 is 5, and all values in the left subtree (3, 5, 7) are less than 10.
The right child of 10 is 15, and all values in the right subtree (15, 20) are greater than 10.
4. No Duplicate Values
A BST in data structure does not contain duplicate values. Each value must be unique to maintain the
order property.
5. Recursive Definition
Each subtree of a BST is also a BST. This means the left and right children of any node are roots of
their own Binary Search Trees.
4. Applications: Useful in databases, file systems, and searching algorithms like binary search.
8b.
Steps:
9a.
AVL Tree and Rotations in Insertion
An AVL tree is a type of self-balancing binary search tree where the balance factor (difference in
heights of the left and right subtrees) of every node is either -1, 0, or 1.
When a new node is inserted into an AVL tree, it might violate the balance condition, causing the
tree to become unbalanced. To restore balance, rotations are used.
1. Insert the Node: Insert the node following the rules of a Binary Search Tree (BST).
o For each node in the path from the inserted node to the root, calculate the balance
factor:
3. Identify the Unbalanced Node: If the balance factor of any node becomes less than -1 or
greater than 1, the tree is unbalanced.
4. Perform Rotations: Based on the structure of the tree, apply one of the four types of
rotations to restore balance.
Process: Rotate the unbalanced node down to the right, and its left child becomes the new
root of the subtree.
10
/\
2 10
2. Left Rotation (Single Rotation)
Process: Rotate the unbalanced node down to the left, and its right child becomes the new
root of the subtree.
10
15
20
15
/ \
10 20
Trigger: Left subtree is too tall, and the imbalance is in the right child of the left subtree
(Left-Right imbalance).
Process:
o First, perform a left rotation on the left child of the unbalanced node.
10
10
/
7
/\
5 10
Trigger: Right subtree is too tall, and the imbalance is in the left child of the right subtree
(Right-Left imbalance).
Process:
o First, perform a right rotation on the right child of the unbalanced node.
10
20
15
10
15
20
15
/ \
10 20
1. Insert 10: 10
2. Insert 20:
10
20
3. Insert 30:
10
20
30
20
/ \
10 30
9b.
Properties of Red-Black Trees
A Red-Black Tree is a type of self-balancing binary search tree that ensures the height of the tree is
logarithmic in terms of the number of nodes. It achieves balance by maintaining certain properties,
each of which must hold true for the tree to be a valid Red-Black Tree.
1. Node Coloring:
2. Root Property:
o A red node cannot have a red parent or a red child (no two consecutive red nodes in
any path).
o For every node, every path from that node to its descendant null pointers (NIL
leaves) must have the same number of black nodes.
5. Leaf Property:
[OR]
[10B]
/ \
[7R] [15B]
/ \ \
There are no two consecutive red nodes (e.g., 15B → 20R is valid).
Every path from the root to any leaf (e.g., 10 → 7 → 5 or 10 → 15 → 20) contains the same
number of black nodes (2 black nodes in this case).
1. Self-Balancing:
2. Efficient Updates:
o Insertions and deletions are efficient, requiring at most a few rotations to restore the
Red-Black properties.
3. Memory Efficiency:
o Unlike AVL trees, Red-Black trees do not require storing the height of each node,
making them slightly more memory-efficient.
o Red-Black trees are particularly effective for applications where the dataset changes
frequently (e.g., insertions and deletions).
o Red-Black trees are widely used in computer science, such as in the implementation
of the map and set data structures in the C++ STL, Java's TreeMap, and Linux kernel.
10.
B-Tree Construction (Order 4)
4. Keys in each node are sorted, and each child subtree contains values in the corresponding range.
Insertion Steps:
Insert 1, 4, 7, 10:
2. Add 1, 4, 7, and 10 into the root node (no splits required yet).
Insert 17:
1. Add 17 to the root node. Now the root contains [1, 4, 7, 10, 17].
Tree:
[7]
/ \
Insert 21:
1. Add 21 to the right child [10, 17]. 2.No splits are required.
Tree:
[7]
/ \
Insert 31:
Tree:
[7, 17]
/ | \
Insert 25:
Tree:
[7, 17]
/ | \
Insert 19:
1. Add 19 to the middle child [10]. 2.The middle child becomes [10, 19].
Tree:
[7, 17]
/ | \
Insert 20:
Tree:
/ | | \
Insert 28:
Tree:
/ | | | \
Insert 42:
/ | | | \
Delete 28:
/ | | | \
Delete 31:
/ | | | \
Delete 21:
/ | | | \
[1, 4] [10] [20] [] [42]
/ | | \
Delete 25:
/ | | \
Delete 19:
[7, 17]
/ | \
[7, 17]
/ | \