From af264f7ed1ea2e09c1ce932f6f3e063750053a3e Mon Sep 17 00:00:00 2001
From: Florian Burgener <florian.brgnr@gmail.com>
Date: Fri, 20 May 2022 00:21:42 +0200
Subject: [PATCH] Deletion step 2

---
 __main__.py | 206 +++++++++++++++++++++++++++-------------------------
 rebu.py     |  89 +++++++++++++++++++++++
 2 files changed, 197 insertions(+), 98 deletions(-)
 create mode 100644 rebu.py

diff --git a/__main__.py b/__main__.py
index 841342a..ca8e13a 100644
--- a/__main__.py
+++ b/__main__.py
@@ -52,7 +52,7 @@ def find_value_index_in_array(array, value):
     return None
 
 
-def array_insert_sorted(array, value):
+def sorted_array_insert(array, value):
     index = lower_bound(array, value)
     array.insert(index, value)
     return index
@@ -95,15 +95,15 @@ def split_leaf(node, key):
     if virtual_insertion_index < median_index:
         median_value = node.keys[median_index - 1]
         redistribute_keys(node, right_node, median_index - 1, median_index - 1)
-        array_insert_sorted(node.keys, key)
+        sorted_array_insert(node.keys, key)
     elif virtual_insertion_index > median_index:
         median_value = node.keys[median_index]
         redistribute_keys(node, right_node, median_index, median_index)
-        array_insert_sorted(right_node.keys, key)
+        sorted_array_insert(right_node.keys, key)
     else:
         median_value = key
         redistribute_keys(node, right_node, median_index, median_index)
-        array_insert_sorted(right_node.keys, key)
+        sorted_array_insert(right_node.keys, key)
 
     if not node.children:
         # The node has no link to the next node, so a link is created.
@@ -132,14 +132,14 @@ def split_internal(node, key, right_child_node):
         median_value = node.keys[median_index - 1]
         redistribute_keys(node, right_node, median_index - 1, median_index)
         redistribute_children(node, right_node, median_index, median_index)
-        inserted_at_index = array_insert_sorted(node.keys, key)
+        inserted_at_index = sorted_array_insert(node.keys, key)
         node.children.insert(inserted_at_index + 1, right_child_node)
     elif virtual_insertion_index > median_index:
         # The key is virtually inserted to the right of the median index.
         median_value = node.keys[median_index]
         redistribute_keys(node, right_node, median_index, median_index + 1)
         redistribute_children(node, right_node, median_index + 1, median_index + 1)
-        inserted_at_index = array_insert_sorted(right_node.keys, key)
+        inserted_at_index = sorted_array_insert(right_node.keys, key)
         right_node.children.insert(inserted_at_index + 1, right_child_node)
     else:
         # The key is virtually inserted at the median index.
@@ -179,7 +179,7 @@ def insert_full(root, parents, node, key, previous_split_right_node):
 
 
 def insert_non_full(node, key, previous_split_right_node):
-    inserted_at_index = array_insert_sorted(node.keys, key)
+    inserted_at_index = sorted_array_insert(node.keys, key)
 
     if previous_split_right_node is not None:
         node.children.insert(inserted_at_index + 1, previous_split_right_node)
@@ -222,123 +222,134 @@ def bptree_find_smallest_key(root):
 
 
 def bptree_shrink(root):
-    right_child = root.children[1]
-    root.keys = right_child.keys
-    root.children = right_child.children
+    child = root.children[0]
+    root.keys = child.keys.copy()
+    root.children = child.children.copy()
+    root.is_leaf = child.is_leaf
 
 
-def bptree_delete_internal(root, parents, node, key):
-    if node != root:
-        parent = parents.pop()
+def bptree_steal_internal():
+    # TODO
+    pass
+
+
+def bptree_steal_leaf(parent, node, child_index, sibling, sibling_side):
+    if sibling_side == "l":
+        sibling_key = sibling.keys[len(sibling.keys) - 1]
+        sorted_array_delete(sibling.keys, sibling_key)
+        sorted_array_insert(node.keys, sibling_key)
+        parent.keys[child_index - 1] = sibling_key
+    elif sibling_side == "r":
+        sibling_key = sibling.keys[0]
+        sorted_array_delete(sibling.keys, sibling_key)
+        sorted_array_insert(node.keys, sibling_key)
+        parent.keys[child_index] = sibling.keys[0]
+
+
+def _bptree_merge(parent, main_node, secondary_node, pivot_index):
+    if not main_node.is_leaf:
+        parent_key = parent.keys[pivot_index]
+        main_node.keys.insert(0, parent_key)
 
-    if len(node.keys) < node.order and node != root:
-        print("Merge 2")
-        # children_index = None
+    for i in reversed(range(len(secondary_node.keys))):
+        main_node.keys.insert(0, secondary_node.keys[i])
 
-        # for i, child in enumerate(parent.children):
-        #     if node == child:
-        #         children_index = i
+    if not main_node.is_leaf:
+        for i in reversed(range(len(secondary_node.children))):
+            main_node.children.insert(0, secondary_node.children[i])
 
-        # if children_index == 0:
-        #     sibling = parent.children[children_index + 1]
-        #     parent_key = parent.keys[children_index]
-        #     parent.keys.pop(find_value_index_in_array(parent.keys, parent_key))
-        #     array_insert_sorted(sibling.keys, parent_key)
-        #     array_insert_sorted(sibling.keys, node.keys[0])
-        #     sibling.children = node.children + sibling.children
-        # else:
-        #     sibling = parent.children[children_index - 1]
-        #     parent_key = parent.keys[children_index - 1]
-        #     parent.keys.pop(find_value_index_in_array(parent.keys, parent_key))
-        #     array_insert_sorted(node.keys, parent_key)
+    parent.keys.pop(pivot_index)
+    parent.children.pop(pivot_index)
 
-        #     for key in sibling.keys:
-        #         array_insert_sorted(node.keys, key)
 
-        #     node.children = sibling.children + node.children
+def bptree_merge(parent, node, child_index, sibling, sibling_side):
+    if sibling_side == "l":
+        # The sibling is merged into the node.
+        _bptree_merge(parent, node, sibling, child_index - 1)
+    elif sibling_side == "r":
+        # The node is merged into the sibling.
+        _bptree_merge(parent, sibling, node, child_index)
 
-        # if parent == root and len(parent.keys) == 0:
-        #     bptree_shrink(root)
 
-    if is_value_in_array(node.keys, key) and len(node.children) > 0:
-        index = find_value_index_in_array(node.keys, key)
-        node.keys[index] = bptree_find_smallest_key(node.children[index + 1])
+def find_child_index(parent, child):
+    for i in range(len(parent.children)):
+        if child == parent.children[i]:
+            return i
 
-    if node != root:
-        bptree_delete_internal(root, parents, parent, key)
+    return None
 
 
-def bptree_find_sibling(parent, children_index):
-    if children_index == 0:
+def bptree_find_sibling(parent, child_index):
+    if child_index == 0:
         # Must take the sibling on the right.
         sibling = parent.children[1]
         sibling_position = "r"
-    elif children_index == 2 * parent.order - 1:
+    elif child_index == len(parent.children) - 1:
         # Must take the sibling on the left.
-        sibling = parent.children[2 * parent.order - 2]
+        sibling = parent.children[len(parent.children) - 2]
         sibling_position = "l"
     else:
         # Can take the sibling from left or right.
-        if len(parent.children[children_index - 1].keys) > parent.order:
+        if len(parent.children[child_index - 1].keys) > parent.order:
             # The left sibling has enough keys to borrow one.
-            sibling = parent.children[children_index - 1]
+            sibling = parent.children[child_index - 1]
             sibling_position = "l"
-        elif len(parent.children[children_index + 1].keys) > parent.order:
+        elif len(parent.children[child_index + 1].keys) > parent.order:
             # The right sibling has enough keys to borrow one.
-            sibling = parent.children[children_index + 1]
+            sibling = parent.children[child_index + 1]
             sibling_position = "r"
         else:
             # A merge between the node and the left sibling is required.
-            sibling = parent.children[children_index - 1]
+            sibling = parent.children[child_index - 1]
+            sibling_position = "l"
 
     return sibling, sibling_position
 
 
-def bptree_delete_leaf(root, parents, leaf, key):
-    if leaf != root:
+def _bptree_delete(root, parents, node, key):
+    parent = None
+
+    if len(parents) > 0:
         parent = parents.pop()
 
-    if len(leaf.keys) > leaf.order or leaf == root:
-        sorted_array_delete(leaf.keys, key)
+    if node.is_leaf:
+        keys_length = len(node.keys)
+        sorted_array_delete(node.keys, key)
+
+        if keys_length == node.order and node != root:
+            child_index = find_child_index(parent, node)
+            sibling, sibling_side = bptree_find_sibling(parent, child_index)
+
+            if len(sibling.keys) == sibling.order:
+                # There is not enough key in the left and right siblings.
+                bptree_merge(parent, node, child_index, sibling, sibling_side)
+
+                if parent == root and len(parent.keys) == 0:
+                    bptree_shrink(root)
+                    parent = None
+            else:
+                # There are enough keys in the sibling to steal one.
+                bptree_steal_leaf(parent, node, child_index, sibling, sibling_side)
     else:
-        deletion_index = find_value_index_in_array(leaf.keys, key)
-        leaf.keys.pop(deletion_index)
-
-        children_index = None
-
-        for i, child in enumerate(parent.children):
-            if leaf == child:
-                children_index = i
-
-        sibling, sibling_position = bptree_find_sibling(parent, children_index)
-
-        if len(sibling.keys) == sibling.order:
-            print("Merge 1")
-            pass
-            # if children_index == 0:
-            #     # Sibling not on the left.
-            #     array_insert_sorted(sibling.keys, leaf.keys[0])
-            #     parent.children.pop(children_index)
-            #     parent.keys.pop(children_index)
-            # else:
-            #     for key in sibling.keys:
-            #         array_insert_sorted(leaf.keys, key)
-
-            #     parent.children.pop(children_index - 1)
-            #     parent.keys.pop(children_index - 1)
-        else:
-            if sibling_position == "l":
-                sibling_key = sibling.keys[len(sibling.keys) - 1]
-                sorted_array_delete(sibling.keys, sibling_key)
-                array_insert_sorted(leaf.keys, sibling_key)
-                parent.keys[children_index - 1] = sibling_key
+        if node != root and len(node.keys) < node.order:
+            child_index = find_child_index(parent, node)
+            sibling, sibling_side = bptree_find_sibling(parent, child_index)
+
+            if len(sibling.keys) == sibling.order:
+                bptree_merge(parent, node, child_index, sibling, sibling_side)
+
+                if parent == root and len(parent.keys) == 0:
+                    bptree_shrink(root)
+                    parent = None
             else:
-                sibling_key = sibling.keys[0]
-                sorted_array_delete(sibling.keys, sibling_key)
-                array_insert_sorted(leaf.keys, sibling_key)
-                parent.keys[children_index] = sibling.keys[0]
+                print("???????????")
+
+        if len(node.children) > 0 and is_value_in_array(node.keys, key):
+            index = find_value_index_in_array(node.keys, key)
+            node.keys[index] = bptree_find_smallest_key(node.children[index + 1])
 
-    bptree_delete_internal(root, parents, parent, key)
+    if parent is not None:
+        _bptree_delete(root, parents, parent, key)
 
 
 def deletion_find_leaf(root, key):
@@ -363,14 +374,13 @@ def bptree_delete(root, key):
     if not is_value_in_array(leaf.keys, key):
         return
 
-    bptree_delete_leaf(root, parents, leaf, key)
+    _bptree_delete(root, parents, leaf, key)
 
 
 # DELETION : END
 
 
 def bptree_search(root, key):
-    # BUG !!!
     if root.is_leaf:
         return is_value_in_array(root.keys, key)
 
@@ -455,19 +465,19 @@ def main():
     #     assert not bptree_search(root, random_key)
 
     root = Node(order)
-    keys = generate_random_keys(18, 1, 99)
+    keys = generate_random_keys(30, 1, 99)
     print(keys)
     print("=====")
 
     for key in keys:
         bptree_insert(root, key)
 
-    bptree_delete(root, 56)
-    bptree_delete(root, 12)
-    bptree_delete(root, 21)
+    bptree_delete(root, 65)
+    bptree_delete(root, 57)
     bptree_delete(root, 47)
-    bptree_delete(root, 11)
-    bptree_delete(root, 86)
+    # bptree_delete(root, 65)
+
+
     bptree_print(root)
 
 
diff --git a/rebu.py b/rebu.py
new file mode 100644
index 0000000..45cc980
--- /dev/null
+++ b/rebu.py
@@ -0,0 +1,89 @@
+def bptree_delete_leaf(root, parents, leaf, key):
+    if leaf != root:
+        parent = parents.pop()
+
+    if len(leaf.keys) > leaf.order or leaf == root:
+        sorted_array_delete(leaf.keys, key)
+    else:
+        deletion_index = find_value_index_in_array(leaf.keys, key)
+        leaf.keys.pop(deletion_index)
+
+        children_index = None
+
+        for i, child in enumerate(parent.children):
+            if leaf == child:
+                children_index = i
+
+        sibling, sibling_position = bptree_find_sibling(parent, children_index)
+
+        if len(sibling.keys) == sibling.order:
+            print("Merge 1")
+            pass
+            # if children_index == 0:
+            #     # Sibling not on the left.
+            #     array_insert_sorted(sibling.keys, leaf.keys[0])
+            #     parent.children.pop(children_index)
+            #     parent.keys.pop(children_index)
+            # else:
+            #     for key in sibling.keys:
+            #         array_insert_sorted(leaf.keys, key)
+
+            #     parent.children.pop(children_index - 1)
+            #     parent.keys.pop(children_index - 1)
+        else:
+            if sibling_position == "l":
+                sibling_key = sibling.keys[len(sibling.keys) - 1]
+                sorted_array_delete(sibling.keys, sibling_key)
+                array_insert_sorted(leaf.keys, sibling_key)
+                parent.keys[children_index - 1] = sibling_key
+            else:
+                sibling_key = sibling.keys[0]
+                sorted_array_delete(sibling.keys, sibling_key)
+                array_insert_sorted(leaf.keys, sibling_key)
+                parent.keys[children_index] = sibling.keys[0]
+
+    bptree_delete_internal(root, parents, parent, key)
+
+
+
+
+
+def bptree_delete_internal(root, parents, node, key):
+    if node != root:
+        parent = parents.pop()
+
+    if len(node.keys) < node.order and node != root:
+        print("Merge 2")
+        # children_index = None
+
+        # for i, child in enumerate(parent.children):
+        #     if node == child:
+        #         children_index = i
+
+        # if children_index == 0:
+        #     sibling = parent.children[children_index + 1]
+        #     parent_key = parent.keys[children_index]
+        #     parent.keys.pop(find_value_index_in_array(parent.keys, parent_key))
+        #     array_insert_sorted(sibling.keys, parent_key)
+        #     array_insert_sorted(sibling.keys, node.keys[0])
+        #     sibling.children = node.children + sibling.children
+        # else:
+        #     sibling = parent.children[children_index - 1]
+        #     parent_key = parent.keys[children_index - 1]
+        #     parent.keys.pop(find_value_index_in_array(parent.keys, parent_key))
+        #     array_insert_sorted(node.keys, parent_key)
+
+        #     for key in sibling.keys:
+        #         array_insert_sorted(node.keys, key)
+
+        #     node.children = sibling.children + node.children
+
+        # if parent == root and len(parent.keys) == 0:
+        #     bptree_shrink(root)
+
+    if is_value_in_array(node.keys, key) and len(node.children) > 0:
+        index = find_value_index_in_array(node.keys, key)
+        node.keys[index] = bptree_find_smallest_key(node.children[index + 1])
+
+    if node != root:
+        bptree_delete_internal(root, parents, parent, key)
-- 
GitLab