B + tree is a variation of the B-tree data structure. In a B + tree, data pointers are stored only at the leaf nodes of the tree. In a B+ tree structure of a leaf node differs from the structure of internal nodes.
When compared to the B tree, B+ Tree offers more effective insertion, deletion, and other operations.Â
Deleting in B+ Tree:
Three operations—Searching, Deleting, and Balancing—are involved in deleting an element from the B+ tree. As the last step, we will balance the tree after first looking for the node that has to be deleted and deleting it from the tree.
A key-value pair is deleted from a B+ tree using this method. In order to keep the attributes of the tree’s internal nodes after performing the deletion operation, the appropriate leaf node and its key-value pair must be removed.Â
Illustration:
Consider the following B+ Tree:
            [ 11 14 20 ]
          /     |        \
     [ 1 3 5 ]  [ 11 12 ]  [ 14 15 17 ]
      /  |  \     /  \     /    |    \
   [ 1 2 ] [ 3 4 ] [ 5 7 ] [ 11 ] [ 12 ] [ 14 15 ]ÂLet’s delete key 5 from the tree.
The deletion strategy for the B+ tree is as follows:
- Look to locate the deleted key in the leaf nodes.
- Delete the key and its associated value if the key is discovered in a leaf node.
- One of the following steps should be taken if the node underflows (number of keys is less than half the maximum allowed):
- Get a key by borrowing it from a sibling node if it contains more keys than the required minimum.
- If the minimal number of keys is met by all of the sibling nodes, merge the underflow node with one of its siblings and modify the parent node as necessary.
- Remove all references to the deleted leaf node from the internal nodes of the tree.
- Remove the old root node and update the new one if the root node is empty.
The following describes how to remove Key 5 from the B+ tree:
- Look in the leaf nodes for the key number 5. The node [1 3 5] contains the key.
- Remove the value associated with the key 5, creating the node [1 3].
- The node [1 3] underflows because it contains fewer keys than the maximum number permitted. From its sibling node, we can obtain a key [3 4]. We borrow key 4 in this instance, resulting in the nodes [1 3 4] and [5 7].
- Remove all references to the deleted leaf node from the internal nodes of the tree. We must delete the reference to the node [1 3 5] from its parent node [1 3 4 11] because it was merged with the node [5 7]. The node [1 3 4 11] is the consequence of this.
- The deletion is finished since the root node [11 14 20] is not empty.
Below is the implementation of the above illustration:
Python3
# Python Implementation class Node:           # Creating structure of tree     def __init__(self, leaf = False):         self.keys = []         self.values = []         self.leaf = leaf         self.next = None  # B + Tree     class BPlusTree:     def __init__(self, degree):         self.root = Node(leaf = True)         self.degree = degree       # Search for key which     # has to be deleted     def search(self, key):         curr = self.root         while not curr.leaf:             i = 0            while i < len(curr.keys):                 if key < curr.keys[i]:                     break                i += 1            curr = curr.values[i]         i = 0        while i < len(curr.keys):             if curr.keys[i] == key:                 return True            i += 1        return False      # Insert key value pairs     def insert(self, key):         curr = self.root         if len(curr.keys) == 2 * self.degree:             new_root = Node()             self.root = new_root             new_root.values.append(curr)             self.split(new_root, 0, curr)             self.insert_non_full(new_root, key)         else:             self.insert_non_full(curr, key)       def insert_non_full(self, curr, key):         i = 0        while i < len(curr.keys):             if key < curr.keys[i]:                 break            i += 1        if curr.leaf:             curr.keys.insert(i, key)         else:             if len(curr.values[i].keys) == 2 * self.degree:                 self.split(curr, i, curr.values[i])                 if key > curr.keys[i]:                     i += 1            self.insert_non_full(curr.values[i], key)       def split(self, parent, i, node):         new_node = Node(leaf = node.leaf)         parent.values.insert(i + 1, new_node)         parent.keys.insert(i, node.keys[self.degree-1])         new_node.keys = node.keys[self.degree:]         node.keys = node.keys[:self.degree-1]         if not new_node.leaf:             new_node.values = node.values[self.degree:]             node.values = node.values[:self.degree]       def steal_from_left(self, parent, i):         node = parent.values[i]         left_sibling = parent.values[i-1]         node.keys.insert(0, parent.keys[i-1])         parent.keys[i-1] = left_sibling.keys.pop(-1)         if not node.leaf:             node.values.insert(0, left_sibling.values.pop(-1))       def steal_from_right(self, parent, i):         node = parent.values[i]         right_sibling = parent.values[i + 1]         node.keys.append(parent.keys[i])         parent.keys[i] = right_sibling.keys.pop(0)         if not node.leaf:             node.values.append(right_sibling.values.pop(0))       # Del the given key     def delete(self, key):         curr = self.root         found = False        i = 0        while i < len(curr.keys):             if key == curr.keys[i]:                 found = True                break            elif key < curr.keys[i]:                 break            i += 1        if found:             if curr.leaf:                 curr.keys.pop(i)             else:                 pred = curr.values[i]                 if len(pred.keys) >= self.degree:                     pred_key = self.get_max_key(pred)                     curr.keys[i] = pred_key                     self.delete_from_leaf(pred_key, pred)                 else:                     succ = curr.values[i + 1]                     if len(succ.keys) >= self.degree:                         succ_key = self.get_min_key(succ)                         curr.keys[i] = succ_key                         self.delete_from_leaf(succ_key, succ)                     else:                         self.merge(curr, i, pred, succ)                         self.delete_from_leaf(key, pred)             if curr == self.root and not curr.keys:                 self.root = curr.values[0]         else:             if curr.leaf:                 return False            else:                 if len(curr.values[i].keys) < self.degree:                     if i != 0 and len(curr.values[i-1].keys) >= self.degree:                         self.steal_from_left(curr, i)                     elif i != len(curr.keys) and len(curr.values[i + 1].keys) >= self.degree:                         self.steal_from_right(curr, i)                     else:                         if i == len(curr.keys):                             i -= 1                        self.merge(curr, i, curr.values[i], curr.values[i + 1])                 self.delete(key)       def delete_from_leaf(self, key, leaf):         leaf.keys.remove(key)         if leaf == self.root or len(leaf.keys) >= self.degree // 2:             return        parent = self.find_parent(leaf)         i = parent.values.index(leaf)         if i > 0 and len(parent.values[i-1].keys) > self.degree // 2:             self.rotate_right(parent, i)         elif i < len(parent.keys) and len(parent.values[i + 1].keys) > self.degree // 2:             self.rotate_left(parent, i)         else:             if i == len(parent.keys):                 i -= 1            self.merge(parent, i, parent.values[i], parent.values[i + 1])       def get_min_key(self, node):         while not node.leaf:             node = node.values[0]         return node.keys[0]       def get_max_key(self, node):         while not node.leaf:             node = node.values[-1]         return node.keys[-1]           def get_min_key(self, node):             while not node.leaf:                 node = node.values[0]                 return node.keys[0]       def merge(self, parent, i, pred, succ):         pred.keys += succ.keys         pred.values += succ.values         parent.values.pop(i + 1)         parent.keys.pop(i)         if parent == self.root and not parent.keys:             self.root = pred       def fix(self, parent, i):         node = parent.values[i]         if i > 0 and len(parent.values[i-1].keys) >= self.degree:             self.rotate_right(parent, i)         elif i < len(parent.keys) and len(parent.values[i + 1].keys) >= self.degree:             self.rotate_left(parent, i)         else:             if i == len(parent.keys):                 i -= 1            self.merge(parent, i, node, parent.values[i + 1])       # Balance the tree after deletion     def rotate_right(self, parent, i):         node = parent.values[i]         prev = parent.values[i-1]         node.keys.insert(0, parent.keys[i-1])         parent.keys[i-1] = prev.keys.pop(-1)         if not node.leaf:             node.values.insert(0, prev.values.pop(-1))       def rotate_left(self, parent, i):         node = parent.values[i]         next = parent.values[i + 1]         node.keys.append(parent.keys[i])         parent.keys[i] = next.keys.pop(0)         if not node.leaf:             node.values.append(next.values.pop(0))       # Function to print Tree     def print_tree(self):         curr_level = [self.root]         while curr_level:             next_level = []             for node in curr_level:                 print(str(node.keys), end =' ')                 if not node.leaf:                     next_level += node.values             print()             curr_level = next_level     # create a B + tree with degree 3 tree = BPlusTree(3)   # insert some keys tree.insert(1) tree.insert(2) tree.insert(3) tree.insert(4) tree.insert(5) tree.insert(6) tree.insert(7) tree.insert(8) tree.insert(9)   # print the tree tree.print_tree() # [4] [2, 3] [6, 7, 8, 9] [1] [5]   # delete a key tree.delete(3)   # print the tree tree.print_tree() # [4] [2] [6, 7, 8, 9] [1] [5] |
[3] [1, 2] [4, 5, 6, 7, 8, 9] [4] [1, 2] [5, 6, 7, 8, 9]
Time Complexity: O(log N)
Auxiliary Space: O(N)
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!
