diff --git a/__main__.py b/__main__.py index dd894ceb9a920d3514fcf75166c168440fa3d316..b542589fb4f6b0342676d431cef25d9620645a3b 100644 --- a/__main__.py +++ b/__main__.py @@ -1,15 +1,5 @@ import random -from numpy import sort - - -class Node: - def __init__(self, order): - self.order = order - self.is_leaf = True - self.keys = [] - self.children = [] - def lower_bound(array, value): low = 0 @@ -45,12 +35,40 @@ def is_value_in_array(array, value): return False +def find_value_index_in_array(array, value): + low = 0 + high = len(array) - 1 + + while low <= high: + m = (low + high) // 2 + + if array[m] < value: + low = m + 1 + elif array[m] > value: + high = m - 1 + else: + return m + + return None + + def array_insert_sorted(array, value): index = lower_bound(array, value) array.insert(index, value) return index +# B+ Tree : START + + +class Node: + def __init__(self, order): + self.order = order + self.is_leaf = True + self.keys = [] + self.children = [] + + def find_leaf(root, key): parents = [] current = root @@ -67,13 +85,7 @@ def node_is_full(node): return len(node.keys) == 2 * node.order -def insert(root, key): - parents, leaf = find_leaf(root, key) - - if node_is_full(leaf): - insert_full(root, parents, leaf, key, None) - else: - insert_non_full(leaf, key, None) +# INSERTION : START def redistribute_keys(left_node, right_node, left_index, right_index): @@ -145,7 +157,7 @@ def split_internal(node, key, right_child_node): return median_value, right_node -def tree_grow(root, median_value, split_right_node): +def bptree_grow(root, median_value, split_right_node): left_node = Node(root.order) left_node.is_leaf = split_right_node.is_leaf left_node.keys = root.keys @@ -162,7 +174,7 @@ def insert_full(root, parents, node, key, previous_split_right_node): median_value, split_right_node = split_internal(node, key, previous_split_right_node) if node == root: - tree_grow(root, median_value, split_right_node) + bptree_grow(root, median_value, split_right_node) else: parent = parents.pop() @@ -179,7 +191,59 @@ def insert_non_full(node, key, previous_split_right_node): node.children.insert(inserted_at_index + 1, previous_split_right_node) -def tree_search(root, key): +def bptree_insert(root, key): + parents, leaf = find_leaf(root, key) + + if node_is_full(leaf): + insert_full(root, parents, leaf, key, None) + else: + insert_non_full(leaf, key, None) + + +# INSERTION : END + +# DELETION : START + + +def bptree_delete(root, key): + parents, leaf = find_leaf(root, key) + + if not is_value_in_array(leaf.keys, key): + return + + if len(leaf.keys) > leaf.order: + deletion_index = find_value_index_in_array(leaf.keys, key) + leaf.keys.pop(deletion_index) + else: + deletion_index = find_value_index_in_array(leaf.keys, key) + leaf.keys.pop(deletion_index) + + parent = parents.pop() + children_index = None + + for i, child in enumerate(parent.children): + if leaf == child: + children_index = i + + if children_index == 0: + sibling = parent.children[children_index + 1] + else: + sibling = parent.children[children_index - 1] + + if len(sibling.keys) == leaf.order: + pass + else: + # Works only if children_index = 0 + borrowed_key = sibling.keys[0] + sibling.keys.pop(0) + leaf.keys.append(borrowed_key) + parent.keys[0] = sibling.keys[0] + + +# DELETION : END + + +def bptree_search(root, key): if root.is_leaf: return is_value_in_array(root.keys, key) @@ -188,10 +252,10 @@ def tree_search(root, key): if children_index < len(root.keys) and root.keys[children_index] == key: children_index += 1 - return tree_search(root.children[children_index], key) + return bptree_search(root.children[children_index], key) -def tree_print(root, depth=0): +def bptree_print(root, depth=0): print(" " * depth, end="") print(root.keys) @@ -199,10 +263,10 @@ def tree_print(root, depth=0): return for child in root.children: - tree_print(child, depth + 1) + bptree_print(child, depth + 1) -def extract_all_keys(root): +def bptree_extract_all_keys(root): current = root while not current.is_leaf: @@ -218,6 +282,9 @@ def extract_all_keys(root): return keys +# B+ Tree : END + + def generate_random_keys(length, min_key, max_key): keys = [] @@ -236,28 +303,41 @@ def main(): random.seed(0) order = 2 - root = Node(order) - keys = generate_random_keys(40, 1, 99) - print(keys) + # root = Node(order) + # keys = generate_random_keys(40, 1, 99) + # print(keys) - for key in keys: - insert(root, key) + # for key in keys: + # bptree_insert(root, key) - tree_print(root) - extracted_keys = extract_all_keys(root) - assert extracted_keys == sorted(keys) + # bptree_print(root) + # extracted_keys = bptree_extract_all_keys(root) + # assert extracted_keys == sorted(keys) - for key in keys: - assert tree_search(root, key) + # for key in keys: + # assert bptree_search(root, key) - for _ in range(5): - while True: - random_key = random.randint(1, 99) + # for _ in range(5): + # while True: + # random_key = random.randint(1, 99) - if random_key not in keys: - break + # if random_key not in keys: + # break + + # assert not bptree_search(root, random_key) + + root = Node(order) + keys = generate_random_keys(8, 1, 99) + print(keys) + print("=====") + + for key in keys: + bptree_insert(root, key) - assert not tree_search(root, random_key) + bptree_delete(root, 51) + # bptree_delete(root, 52) + bptree_delete(root, 34) + bptree_print(root) if __name__ == "__main__":