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