Deletion in B+ Tree

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 zambiatek!



