diff --git a/__main__.py b/__main__.py index 66507d0ed76dbc31b5dc975b8649fcc3a647490b..e4d7be275907b2f0e7122281df9a5a7c0d32a966 100644 --- a/__main__.py +++ b/__main__.py @@ -224,6 +224,10 @@ def bptree_find_smallest_key(root): return bptree_find_smallest_key(root.children[0]) +def is_sibling_left_side(parent, node, sibling): + return find_child_index(parent, sibling) < find_child_index(parent, node) + + def bptree_shrink(root): child = root.children[0] root.keys = child.keys.copy() @@ -231,26 +235,37 @@ def bptree_shrink(root): root.is_leaf = child.is_leaf -def bptree_steal_internal(): - # TODO - pass +def bptree_steal_internal(parent, node, child_index, sibling): + if is_sibling_left_side(parent, node, sibling): + node.keys.insert(0, parent.keys[child_index - 1]) + parent.keys[child_index - 1] = sibling.keys[len(sibling.keys) - 1] + sibling.keys.pop(len(sibling.keys) - 1) + node.children.insert(0, sibling.children[len(sibling.children) - 1]) + sibling.children.pop(len(sibling.children) - 1) + else: + node.keys.append(parent.keys[child_index]) + parent.keys[child_index] = sibling.keys[0] + sibling.keys.pop(0) + node.children.append(sibling.children[0]) + sibling.children.pop(0) -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) +def bptree_steal_leaf(parent, node, child_index, sibling): + if is_sibling_left_side(parent, node, sibling): + stealed_key = sibling.keys[len(sibling.keys) - 1] + sibling.keys.pop(len(sibling.keys) - 1) + parent.keys[child_index - 1] = stealed_key + node.keys.insert(0, stealed_key) + else: + stealed_key = sibling.keys[0] + sibling.keys.pop(0) parent.keys[child_index] = sibling.keys[0] + node.keys.append(stealed_key) def _bptree_merge(parent, main_node, secondary_node, pivot_index): if not main_node.is_leaf: + print(pivot_index) parent_key = parent.keys[pivot_index] main_node.keys.insert(0, parent_key) @@ -265,11 +280,13 @@ def _bptree_merge(parent, main_node, secondary_node, pivot_index): parent.children.pop(pivot_index) -def bptree_merge(parent, node, child_index, sibling, sibling_side): - if sibling_side == "l": +def bptree_merge(parent, node, sibling): + child_index = find_child_index(parent, node) + + if is_sibling_left_side(parent, node, sibling): # The sibling is merged into the node. _bptree_merge(parent, node, sibling, child_index - 1) - elif sibling_side == "r": + else: # The node is merged into the sibling. _bptree_merge(parent, sibling, node, child_index) @@ -282,31 +299,24 @@ def find_child_index(parent, child): return None -def bptree_find_sibling(parent, child_index): +def bptree_find_sibling(parent, node): + child_index = find_child_index(parent, node) + if child_index == 0: # Must take the sibling on the right. - sibling = parent.children[1] - sibling_position = "r" - elif child_index == len(parent.children) - 1: + return parent.children[1] + if child_index == len(parent.children) - 1: # Must take the sibling on the left. - sibling = parent.children[len(parent.children) - 2] - sibling_position = "l" - else: + return parent.children[len(parent.children) - 2] # Can take the sibling from left or right. - if len(parent.children[child_index - 1].keys) > parent.order: - # The left sibling has enough keys to borrow one. - sibling = parent.children[child_index - 1] - sibling_position = "l" - elif len(parent.children[child_index + 1].keys) > parent.order: - # The right sibling has enough keys to borrow one. - sibling = parent.children[child_index + 1] - sibling_position = "r" - else: - # A merge between the node and the left sibling is required. - sibling = parent.children[child_index - 1] - sibling_position = "l" - - return sibling, sibling_position + if len(parent.children[child_index - 1].keys) > parent.order: + # The left sibling has enough keys to borrow one. + return parent.children[child_index - 1] + if len(parent.children[child_index + 1].keys) > parent.order: + # The right sibling has enough keys to borrow one. + return parent.children[child_index + 1] + # A merge between the node and the left sibling is required. + return parent.children[child_index - 1] def _bptree_delete(root, parents, node, key): @@ -316,40 +326,27 @@ def _bptree_delete(root, parents, node, key): parent = parents.pop() 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: - 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 node != root and len(node.keys) < node.order: + child_index = find_child_index(parent, node) + sibling = bptree_find_sibling(parent, node) - if len(sibling.keys) == sibling.order: - bptree_merge(parent, node, child_index, sibling, sibling_side) + if len(sibling.keys) == sibling.order: + bptree_merge(parent, node, sibling) - if parent == root and len(parent.keys) == 0: - bptree_shrink(root) - parent = None + if parent == root and len(parent.keys) == 0: + bptree_shrink(root) + parent = None + else: + if node.is_leaf: + bptree_steal_leaf(parent, node, child_index, sibling) else: - print("???????????") + bptree_steal_internal(parent, node, child_index, sibling) - 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]) + if not node.is_leaf and 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]) if parent is not None: _bptree_delete(root, parents, parent, key) @@ -442,16 +439,17 @@ def generate_random_keys(length, min_key, max_key): def main(): a = 2 random.seed(a) - order = 2 - root = Node(order) - keys = generate_random_keys(40, 1, 99) - print(keys) + # ===================================================================== - for key in keys: - bptree_insert(root, key) + # root = Node(order) + # keys = generate_random_keys(40, 1, 99) + # print(keys) - bptree_print(root) + # for key in keys: + # bptree_insert(root, key) + + # bptree_print(root) # extracted_keys = bptree_extract_all_keys(root) # assert extracted_keys == sorted(keys) @@ -467,20 +465,27 @@ def main(): # assert not bptree_search(root, random_key) - # root = Node(order) - # keys = generate_random_keys(30, 1, 99) - # print(keys) - # print("=====") + # ===================================================================== - # for key in keys: - # bptree_insert(root, key) + root = Node(order) + keys = generate_random_keys(30, 1, 99) + print(keys) + print("=====") - # bptree_delete(root, 65) - # bptree_delete(root, 57) - # bptree_delete(root, 47) - # # bptree_delete(root, 65) + for key in keys: + bptree_insert(root, key) - # bptree_print(root) + bptree_delete(root, 65) + bptree_delete(root, 57) + bptree_delete(root, 47) + bptree_delete(root, 28) + bptree_delete(root, 51) + bptree_insert(root, 100) + bptree_delete(root, 48) + bptree_delete(root, 41) + bptree_delete(root, 60) + + bptree_print(root) if __name__ == "__main__": diff --git a/src/Array.c b/src/Array.c index e9d75d65b206a61a886d7053dc694acec2d885b8..c6a437e543813f7c5599e79ec4f745bbc9f962c8 100644 --- a/src/Array.c +++ b/src/Array.c @@ -87,6 +87,14 @@ bool IntegerArray_binary_search(IntegerArray *array, uint64_t item, int *index) return *index != -1; } +void IntegerArray_delete_at_index(IntegerArray *array, int index) { + for (int i = index; i < array->size; i++) { + array->items[i] = array->items[i + 1]; + } + + array->size--; +} + void IntegerArray_print(IntegerArray *array) { printf("["); diff --git a/src/Array.h b/src/Array.h index e48817e428719ca779c474cea4e4b85818f086c6..99f19602017854ee6fc9affabb16e15985470d5e 100644 --- a/src/Array.h +++ b/src/Array.h @@ -21,6 +21,7 @@ void IntegerArray_insert_at_index(IntegerArray *array, int index, uint64_t item) void IntegerArray_append(IntegerArray *array, uint64_t item); bool IntegerArray_binary_search(IntegerArray *array, uint64_t item, int *index); void IntegerArray_delete_sorted(IntegerArray *array, uint64_t item); +void IntegerArray_delete_at_index(IntegerArray *array, int index); void IntegerArray_print(IntegerArray *array); void IntegerArray_clear(IntegerArray *array); void IntegerArray_copy(IntegerArray *src, IntegerArray *dest); diff --git a/src/BPTree.c b/src/BPTree.c index 50a78b538bafb3de6230762e88961769acc8eae7..de6852a35e1423d5cbeee3cc3675f732ba0f4de9 100644 --- a/src/BPTree.c +++ b/src/BPTree.c @@ -259,3 +259,138 @@ void BPTree_insert(BPTreeNode *root, uint64_t key, uint64_t data) { } // Deletion + +static uint64_t find_smallest_key(BPTreeNode *root); +static int find_child_index(BPTreeNode *parent, BPTreeNode *child); +static bool is_sibling_left_side(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling); +static void shrink(BPTreeNode *root); +static void steal_internal(BPTreeNode *parent, BPTreeNode *node, int child_index, BPTreeNode *sibling); +static void steal_leaf(BPTreeNode *parent, BPTreeNode *node, int child_index, BPTreeNode *sibling); +static void _bptree_merge(BPTreeNode *parent, BPTreeNode *main_node, BPTreeNode *secondary_node, int pivot_index); +static void bptree_merge(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling); +static BPTreeNode *find_sibling(BPTreeNode *parent, BPTreeNode *node); + + static uint64_t find_smallest_key(BPTreeNode *root) { + if (root->is_leaf) { + return root->keys->items[0]; + } + + return find_smallest_key(root->children->items[0]); +} + +static int find_child_index(BPTreeNode *parent, BPTreeNode *child) { + for (int i = 0; i < parent->children->size; i++) { + if (child == parent->children->items[i]) { + return i; + } + } + + return -1; +} + +static bool is_sibling_left_side(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling) { + return find_child_index(parent, sibling) < find_child_index(parent, node); +} + +static void shrink(BPTreeNode *root) { + BPTreeNode *child = root->children->items[0]; + root->is_leaf = child->is_leaf; + + // No keys, it's obvious + // IntegerArray_clear(root->keys); + IntegerArray_copy(child->keys, root->keys); + + BPTreeNodeArray_clear(root->children); + BPTreeNodeArray_copy(child->children, root->children); + + BPTreeNodeArray_clear(child->children); + BPTree_destroy(&child); +} + +static void steal_internal(BPTreeNode *parent, BPTreeNode *node, int child_index, BPTreeNode *sibling) { + if (is_sibling_left_side(parent, node, sibling)) { + IntegerArray_insert_at_index(node->keys, 0, parent->keys->items[child_index - 1]); + parent->keys->items[child_index - 1] = sibling->keys->items[sibling->keys->size - 1]; + IntegerArray_delete_at_index(sibling->keys, sibling->keys->size - 1); + BPTreeNodeArray_insert_at_index(node->children, 0, sibling->children->items[sibling->children->size - 1]); + BPTreeNodeArray_delete_at_index(sibling->children, sibling->children->size - 1); + } else { + IntegerArray_append(node->keys, parent->keys->items[child_index]); + parent->keys->items[child_index] = sibling->keys->items[0]; + IntegerArray_delete_at_index(sibling->keys, 0); + BPTreeNodeArray_append(node->children, sibling->children->items[0]); + BPTreeNodeArray_delete_at_index(sibling->children, 0); + } +} + +static void steal_leaf(BPTreeNode *parent, BPTreeNode *node, int child_index, BPTreeNode *sibling) { + if (is_sibling_left_side(parent, node, sibling)) { + uint64_t stealed_key = sibling->keys->items[sibling->keys->size - 1]; + IntegerArray_delete_at_index(sibling->keys, sibling->keys->size - 1); + parent->keys->items[child_index - 1] = stealed_key; + IntegerArray_insert_at_index(node->keys, 0, stealed_key); + } else { + uint64_t stealed_key = sibling->keys->items[0]; + IntegerArray_delete_at_index(sibling->keys, 0); + parent->keys->items[child_index] = sibling->keys->items[0]; + IntegerArray_append(node->keys, stealed_key); + } +} + +static void _bptree_merge(BPTreeNode *parent, BPTreeNode *main_node, BPTreeNode *secondary_node, int pivot_index) { + if (!main_node->is_leaf) { + IntegerArray_insert_at_index(main_node->keys, 0, parent->keys->items[pivot_index]); + } + + for (int i = secondary_node->keys->size - 1; i >= 0; i--) { + IntegerArray_insert_at_index(main_node->keys, 0, secondary_node->keys->items[i]); + } + + if (!main_node->is_leaf) { + for (int i = secondary_node->children->size - 1; i >= 0; i--) { + BPTreeNodeArray_insert_at_index(main_node->children, 0, secondary_node->children->items[i]); + } + } + + IntegerArray_delete_at_index(parent->keys, pivot_index); + BPTreeNodeArray_delete_at_index(parent->children, pivot_index); +} + +static void bptree_merge(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling) { + int child_index = find_child_index(parent, node); + + if (is_sibling_left_side(parent, node, sibling)) { + _bptree_merge(parent, node, sibling, child_index - 1); + } else { + _bptree_merge(parent, sibling, node, child_index); + } +} + +static BPTreeNode *find_sibling(BPTreeNode *parent, BPTreeNode *node) { + int child_index = find_child_index(parent, node); + + if (child_index == 0) { + return parent->children->items[1]; + } + + if (child_index == parent->children->size - 1) { + return parent->children->items[parent->children->size - 2]; + } + + if (parent->children->items[child_index - 1]->keys->size > parent->order) { + return parent->children->items[child_index - 1]; + } + + if (parent->children->items[child_index + 1]->keys->size > parent->order) { + return parent->children->items[child_index + 1]; + } + + return parent->children->items[child_index - 1]; +} + +static void _bptree_delete(BPTreeNode *root, BPTreeNodeArray *parents, BPTreeNode *node, uint64_t key) { + BPTreeNode *parent = NULL; +} + +void BPTree_delete(BPTreeNode *root, uint64_t key) { +} diff --git a/src/BPTree.h b/src/BPTree.h index 41962bf7fba8e3fb22e561e5ed0bd38ed85934b1..2c83b499629a5f195895f6ac10927aa5b17c77f0 100644 --- a/src/BPTree.h +++ b/src/BPTree.h @@ -27,4 +27,6 @@ void BPTree_insert(BPTreeNode *root, uint64_t key, uint64_t data); // Deletion +void BPTree_delete(BPTreeNode *root, uint64_t key); + #endif