![]() |
VOOZH | about |
In C++, B-trees are balanced tree data structures that maintain sorted data and allow searches, sequential access, insertions, and deletions in logarithmic time. B-trees are generalizations of binary search trees (BST) in that a node can have more than two children. B-trees are optimized for systems that read and write large blocks of data. In this article, we will learn how to implement a B-tree in C++ programming language.
A B-tree is a self-balancing search tree where nodes can have multiple children. It maintains balance by ensuring all leaf nodes are at the same level. The number of children of a node is constrained to a predefined range.
A B-tree has the following properties:
A B-tree can be implemented using a node structure that contains an array of keys and an array of child pointers. The number of keys in a node is always one less than the number of child pointers. The following diagram represents the structure of a B-tree:'
To represent a B-Tree in C++, we will use a classBTreeNode to define the node structure and another class BTree to implement the B-tree operations. We'll implement a class template to keep the B-tree generic so that it can store multiple data types.
template <typename T>
class BTreeNode {
public:
T* keys;
int t;
BTreeNode<T>** Children;
int n;
bool leaf;
};
here:
Following are some of the common applications of the B-Tree in C++:
Operation Name | Description | Time Complexity | Space complexity |
|---|---|---|---|
Insert | Inserts a new element into the tree | O(log n) | O(1) |
Delete Node | Deletes a given node from the tree | O(log n) | O(1) |
Search | Searches for an element in the tree | O(log n) | O(1) |
Traverse | Traverses the B-Tree and prints the elements | O(n) | O(1) |
Split Child | Splits a full child node during insertion of a node | O(1) | O(1) |
Merge | Combine two under-full sibling nodes and a parent key into a single node | O(log n) | O(1) |
Borrow | Transfer a key between sibling nodes via the parent to balance node occupancy. | O(log n) | O(1) |
- If the root is full, create a new root and split the old root.
- Call insertNonFull on the appropriate node.
- In insertNonFull:
- If the node is a leaf, insert the key in the correct position.
- If the node is not a leaf, find the correct child and:
- If the child is full, split it.
- Recursively call insertNonFull on the appropriate child.
- Search for the key to be deleted.
- If the key is in a leaf node:
- Remove the key if the node has more than minimum keys.
- If not, borrow a key from a sibling or merge with a sibling.
- If the key is in an internal node:
- Replace with predecessor or successor from the appropriate child.
- Recursively delete the predecessor or successor.
- Ensure all nodes maintain the minimum number of keys.
- If the root is left with no keys, make its only child the new root.
- Start from the root.
- For each node:
- If the key is present in the node, return the node.
- If the node is a leaf, return null.
- Recursively search the appropriate child.
- Start from the root node.
- For each node:
- Traverse i-th child.
- Print i-th key.
- Repeat for all keys and children.
Splitting occurs when a node becomes full and needs to be divided into two nodes.
Consider a B-tree of order 5 (maximum 4 keys per node). Let's say we have a full node:
[10 | 20 | 30 | 40]When we try to insert 25, we need to split this node.We will follow the below steps to do this:
After splitting:
[30]
/ \
[10 | 20] [40]
And then we can insert 25:
[30]
/ \
[10 | 20 | 25] [40]
- Create a new node.
- Move the upper half of the keys from the full node to the new node.
- If the full node is not a leaf, move the corresponding children as well.
- Insert the middle key into the parent node.
- Update the parent's child pointers to include the new node.
Merging occurs when a node has fewer than the minimum required keys and can't borrow from siblings.
Consider a B-tree of order 3 (minimum 1 key per node). Let's say we have this situation:
[30]
/ \
[10] [40]
If we need to delete 40, we can't leave an empty node. So, we merge the remaining nodes:
[10 | 30]
- Identify the two nodes to be merged and their parent.
- If merging with right sibling:
- Move the separating key from the parent to the end of the left node.
- Copy all keys and child pointers from the right node to the left node.
- Update the parent to remove the separating key and the pointer to the right node.
- If merging with left sibling:
- Move the separating key from the parent to the end of the left node.
- Copy all keys and child pointers from the current node to the left node.
- Update the parent to remove the separating key and the pointer to the current node.
- Delete the empty node.
- If the parent is now under-full, recursively apply merge or borrow operations to it.
Borrowing occurs when a node has fewer than the minimum required keys but can take a key from a sibling.
Consider a B-tree of order 3:
[30]
/ \
[10 | 20] [40]
If we need to delete 40, instead of merging, we can borrow it to the other node:
[20]
/ \
[10] [30 | 40]
- Identify the borrowing node, the sibling to borrow from, and their parent.
- If borrowing from right sibling:
- Move the separating key from the parent to the end of the current node.
- Move the first key from the right sibling to the parent as the new separating key.
- If the sibling is not a leaf, move its first child pointer to be the last child pointer of the current node.
- If borrowing from left sibling:
- Move the separating key from the parent to the start of the current node.
- Move the last key from the left sibling to the parent as the new separating key.
- If the sibling is not a leaf, move its last child pointer to be the first child pointer of the current node.
- Update key counts for both nodes.
The following program demonstrates the implementation of B-Tree in C++:
Output
Traversal of the constructed tree is: 5 7 17
6 is not found
15 is not found
The key 6 is not present in the tree
Traversal of the tree after removing 6: 5 7 17
The key 13 is not present in the tree
Traversal of the tree after removing 13: 5 7 17
Following are some of the common applications of a B-Tree: