
Data Structure
Networking
RDBMS
Operating System
Java
MS Excel
iOS
HTML
CSS
Android
Python
C Programming
C++
C#
MongoDB
MySQL
Javascript
PHP
- Selected Reading
- UPSC IAS Exams Notes
- Developer's Best Practices
- Questions and Answers
- Effective Resume Writing
- HR Interview Questions
- Computer Glossary
- Who is Who
C++ Program to Implement B+ Tree
A B+ tree is an m-tree that consists of a root, internal nodes, and leaves. The root may be a leaf or a node with two or more children. A B+ tree is an advanced data structure that extends the B-tree by adding a linked list of leaf nodes.
A B+ tree can be a B-tree where each node contains only keys (not key-value pairs).
What is B+ Tree?
A B+ tree is a self-balancing tree data structure that maintains sorted data and allows for efficient insertion, deletion, and search operations. It differs from a B-tree in the following ways:
- All values are at the leaf level.
- Leaf nodes are linked, making range queries and sequential access more efficient.
Following is the diagram of B+ tree:

Properties of B+ Tree
A B+ tree of order m has the following properties:
- All leaf node at the same level.
- All internal nodes except the root have at least [m/2] Children. But the root has at least two children it is not a leaf node.
- All internal nodes have at most m children.
- Each internal node with k children contains k-1 keys.
- All leaf nodes contain between [m/2] and m keys.
- The keys in leaf nodes are sorted, and each leaf node has a pointer to the next leaf node.
Implement B+ Tree in C++
A B+ tree contains internal nodes and leaf nodes. The internal node contains a key and a pointer to the child node, while the leaf node stores keys and pointers to the actual data values.
To construct a B+ tree in C++, we will use a class that contains the required definition: A struct to represent each node and a member function to provide basic functionality.
template <typename T> class B_plus_tree { public: struct Node { bool isLeaf; vector<T> keys; vector<Node*> children; Node* next; };
Operations of B+ Tree
The following are some of the basic operations of the B+ tree that are needed to manipulate its elements.
Operation | Description | Time Complexity |
---|---|---|
Insert | Insert a new element into the B+ tree. | O(logn) |
Delete | Remove an element from the B+ tree. | O(logn) |
Search | Searches for the element in the B+ tree. | O(logn) |
Range Query | Retrieve all elements within the given range from the B+ Tree. | O(logn+k) |
Split Child | It split a full child node during insertion. | O(1) |
Example
In the following example, we demonstrate the implementation of a B+ tree in C++ -
#include <algorithm> #include <iostream> #include <vector> using namespace std; template < typename T > class B_plus_tree { public: // structure to create a node struct Node { bool isLeaf; vector < T > keys; vector < Node * > children; Node * next; Node(bool leaf = false): isLeaf(leaf), next(nullptr) {} }; Node * root; int t; // Function for split void splitChild(Node * parent, int index, Node * child); // Function for insert void insertNonFull(Node * node, T key); // Function for remove void remove(Node * node, T key); // Function for borrow void borrowFromPrev(Node * node, int index); // Function for borrow a key from the next sibling void borrowFromNext(Node * node, int index); // Function for merge two nodes void merge(Node * node, int index); void printTree(Node * node, int level); public: B_plus_tree(int degree): root(nullptr), t(degree) {} void insert(T key); bool search(T key); void remove(T key); vector < T > rangeQuery(T lower, T upper); void printTree(); }; // Implementation of splitChild function template < typename T > void B_plus_tree < T > ::splitChild(Node * parent, int index, Node * child) { Node * newChild = new Node(child -> isLeaf); parent -> children.insert( parent -> children.begin() + index + 1, newChild); parent -> keys.insert(parent -> keys.begin() + index, child -> keys[t - 1]); newChild -> keys.assign(child -> keys.begin() + t, child -> keys.end()); child -> keys.resize(t - 1); if (!child -> isLeaf) { newChild -> children.assign(child -> children.begin() + t, child -> children.end()); child -> children.resize(t); } if (child -> isLeaf) { newChild -> next = child -> next; child -> next = newChild; } } // Implementation of insertNonFull function template < typename T > void B_plus_tree < T > ::insertNonFull(Node * node, T key) { if (node -> isLeaf) { node -> keys.insert(upper_bound(node -> keys.begin(), node -> keys.end(), key), key); } else { int i = node -> keys.size() - 1; while (i >= 0 && key < node -> keys[i]) { i--; } i++; if (node -> children[i] -> keys.size() == 2 * t - 1) { splitChild(node, i, node -> children[i]); if (key > node -> keys[i]) { i++; } } insertNonFull(node -> children[i], key); } } // Implementation of remove function template < typename T > void B_plus_tree < T > ::remove(Node * node, T key) { // If node is a leaf if (node -> isLeaf) { auto it = find(node -> keys.begin(), node -> keys.end(), key); if (it != node -> keys.end()) { node -> keys.erase(it); } } else { int idx = lower_bound(node -> keys.begin(), node -> keys.end(), key) - node -> keys.begin(); if (idx < node -> keys.size() && node -> keys[idx] == key) { if (node -> children[idx] -> keys.size() >= t) { Node * predNode = node -> children[idx]; while (!predNode -> isLeaf) { predNode = predNode -> children.back(); } T pred = predNode -> keys.back(); node -> keys[idx] = pred; remove(node -> children[idx], pred); } else if (node -> children[idx + 1] -> keys.size() >= t) { Node * succNode = node -> children[idx + 1]; while (!succNode -> isLeaf) { succNode = succNode -> children.front(); } T succ = succNode -> keys.front(); node -> keys[idx] = succ; remove(node -> children[idx + 1], succ); } else { merge(node, idx); remove(node -> children[idx], key); } } else { if (node -> children[idx] -> keys.size() < t) { if (idx > 0 && node -> children[idx - 1] -> keys.size() >= t) { borrowFromPrev(node, idx); } else if (idx < node -> children.size() - 1 && node -> children[idx + 1] -> keys.size() >= t) { borrowFromNext(node, idx); } else { if (idx < node -> children.size() - 1) { merge(node, idx); } else { merge(node, idx - 1); } } } remove(node -> children[idx], key); } } } // Implementation of borrowFromPrev function template < typename T > void B_plus_tree < T > ::borrowFromPrev(Node * node, int index) { Node * child = node -> children[index]; Node * sibling = node -> children[index - 1]; child -> keys.insert(child -> keys.begin(), node -> keys[index - 1]); node -> keys[index - 1] = sibling -> keys.back(); sibling -> keys.pop_back(); if (!child -> isLeaf) { child -> children.insert(child -> children.begin(), sibling -> children.back()); sibling -> children.pop_back(); } } // Implementation of borrowFromNext function template < typename T > void B_plus_tree < T > ::borrowFromNext(Node * node, int index) { Node * child = node -> children[index]; Node * sibling = node -> children[index + 1]; child -> keys.push_back(node -> keys[index]); node -> keys[index] = sibling -> keys.front(); sibling -> keys.erase(sibling -> keys.begin()); if (!child -> isLeaf) { child -> children.push_back( sibling -> children.front()); sibling -> children.erase(sibling -> children.begin()); } } // Implementation of merge function template < typename T > void B_plus_tree < T > ::merge(Node * node, int index) { Node * child = node -> children[index]; Node * sibling = node -> children[index + 1]; child -> keys.push_back(node -> keys[index]); child -> keys.insert(child -> keys.end(), sibling -> keys.begin(), sibling -> keys.end()); if (!child -> isLeaf) { child -> children.insert(child -> children.end(), sibling -> children.begin(), sibling -> children.end()); } node -> keys.erase(node -> keys.begin() + index); node -> children.erase(node -> children.begin() + index + 1); delete sibling; } // Implementation of printTree function template < typename T > void B_plus_tree < T > ::printTree(Node * node, int level) { if (node != nullptr) { for (int i = 0; i < level; ++i) { cout << " "; } for (const T & key: node -> keys) { cout << key << " "; } cout << endl; for (Node * child: node -> children) { printTree(child, level + 1); } } } // Implementation of printTree wrapper function template < typename T > void B_plus_tree < T > ::printTree() { printTree(root, 0); } // Implementation of search function template < typename T > bool B_plus_tree < T > ::search(T key) { Node * current = root; while (current != nullptr) { int i = 0; while (i < current -> keys.size() && key > current -> keys[i]) { i++; } if (i < current -> keys.size() && key == current -> keys[i]) { return true; } if (current -> isLeaf) { return false; } current = current -> children[i]; } return false; } // Implementation of range query function template < typename T > vector < T > B_plus_tree < T > ::rangeQuery(T lower, T upper) { vector < T > result; Node * current = root; while (!current -> isLeaf) { int i = 0; while (i < current -> keys.size() && lower > current -> keys[i]) { i++; } current = current -> children[i]; } while (current != nullptr) { for (const T & key: current -> keys) { if (key >= lower && key <= upper) { result.push_back(key); } if (key > upper) { return result; } } current = current -> next; } return result; } // Implementation of insert function template < typename T > void B_plus_tree < T > ::insert(T key) { if (root == nullptr) { root = new Node(true); root -> keys.push_back(key); } else { if (root -> keys.size() == 2 * t - 1) { Node * newRoot = new Node(); newRoot -> children.push_back(root); splitChild(newRoot, 0, root); root = newRoot; } insertNonFull(root, key); } } // Implementation of remove function template < typename T > void B_plus_tree < T > ::remove(T key) { if (root == nullptr) { return; } remove(root, key); if (root -> keys.empty() && !root -> isLeaf) { Node * tmp = root; root = root -> children[0]; delete tmp; } } // Main function to test the B+ Tree implementation int main() { B_plus_tree < int > tree(3); // Insert elements tree.insert(1); tree.insert(2); tree.insert(5); tree.insert(7); tree.insert(9); tree.insert(11); cout << "B+ Tree after insertions:" << endl; tree.printTree(); // Search for a key int searchKey = 9; cout << "\nSearching for key " << searchKey << ": " << (tree.search(searchKey) ? "Found" : "Not Found") << endl; // Perform a range query int lower = 1, upper = 11; vector < int > rangeResult = tree.rangeQuery(lower, upper); cout << "\nRange query [" << lower << ", " << upper << "]: "; for (int key: rangeResult) { cout << key << " "; } cout << endl; // Remove a key int removeKey = 7; tree.remove(removeKey); cout << "\nB+ Tree after removing " << removeKey << ":" << endl; tree.printTree(); return 0; }
Following is the B+ tree -
B+ Tree after insertions: 5 1 2 7 9 11 Searching for key 9: Found Range query [1, 11]: 1 2 7 9 11 B+ Tree after removing 7: 5 1 2 9 11