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!