diff --git a/src/Array.c b/src/Array.c index 6c4eb3f330fc6745a361662f833deae0882a1849..81d834904e256aa23f61d6318319280349605cd5 100644 --- a/src/Array.c +++ b/src/Array.c @@ -149,6 +149,16 @@ void BPTreeNodeArray_append(BPTreeNodeArray *array, BPTreeNode *item) { array->size++; } +int BPTreeNodeArray_search(BPTreeNodeArray *array, BPTreeNode *item) { + for (int i = 0; i < array->size; i++) { + if (array->items[i] == item) { + return i; + } + } + + return -1; +} + void BPTreeNodeArray_delete_at_index(BPTreeNodeArray *array, int index) { for (int i = index; i < array->size - 1; i++) { array->items[i] = array->items[i + 1]; diff --git a/src/Array.h b/src/Array.h index 2b68403970c2e287f1bdbb91c91293183b37b887..f59ccf0329254b7ba0303c7b266ff3c6376ed187 100644 --- a/src/Array.h +++ b/src/Array.h @@ -39,6 +39,7 @@ void BPTreeNodeArray_destroy(BPTreeNodeArray **array); void BPTreeNodeArray_insert_at_index(BPTreeNodeArray *array, int index, BPTreeNode *item); void BPTreeNodeArray_append(BPTreeNodeArray *array, BPTreeNode *item); +int BPTreeNodeArray_search(BPTreeNodeArray *array, BPTreeNode *item); void BPTreeNodeArray_delete_at_index(BPTreeNodeArray *array, int index); BPTreeNode *BPTreeNodeArray_pop(BPTreeNodeArray *array); void BPTreeNodeArray_clear(BPTreeNodeArray *array); diff --git a/src/BPTree.c b/src/BPTree.c index 32d82bac5efcbbc567afd022b6d038683febd7a2..9c984e39af841ada2bd3ecb8e8c7677e79c2b6fb 100644 --- a/src/BPTree.c +++ b/src/BPTree.c @@ -33,7 +33,7 @@ static BPTreeNode *find_leaf(BPTreeNode *root, uint64_t key, BPTreeNodeArray **p return current; } -// ======= +// BPTreeNode static void BPTreeNode_destroy(BPTreeNode **node) { IntegerArray_destroy(&(*node)->keys); @@ -43,7 +43,7 @@ static void BPTreeNode_destroy(BPTreeNode **node) { *node = NULL; } -// ======= +// BPTree BPTreeNode *BPTree_init(int order) { BPTreeNode *root = (BPTreeNode *)malloc(sizeof(BPTreeNode)); @@ -102,7 +102,7 @@ bool BPTree_search(BPTreeNode *root, uint64_t key, uint64_t *data) { return BPTree_search(root->children->items[child_index], key, data); } -// Insertion +// BPTree : Insertion static void redistribute_keys(BPTreeNode *left_node, BPTreeNode *right_node, int left_index, int right_index); static void redistribute_children(BPTreeNode *left_node, BPTreeNode *right_node, int left_index, int right_index); @@ -269,41 +269,68 @@ void BPTree_insert(BPTreeNode *root, uint64_t key, uint64_t data) { BPTreeNodeArray_destroy(&parents); } -// Deletion +// BPTree : Deletion +static bool _BPTree_delete(BPTreeNode *node, uint64_t key, BPTreeNode *parent); +static BPTreeNode *traverse(BPTreeNode *node, uint64_t key); 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 _merge(BPTreeNode *parent, BPTreeNode *main_node, BPTreeNode *secondary_node, int pivot_index); -static void merge(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling); -static BPTreeNode *find_sibling(BPTreeNode *parent, BPTreeNode *node); -static bool _BPTree_delete(BPTreeNode *root, uint64_t key, BPTreeNode *parent); -static BPTreeNode *traverse(BPTreeNode *root, uint64_t key); static void deletion_rebalance(BPTreeNode *root, BPTreeNode *parent); +static BPTreeNode *find_sibling(BPTreeNode *parent, BPTreeNode *node); +static void merge(BPTreeNode *parent, BPTreeNode *left_node, BPTreeNode *right_node); +static void steal_leaf(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling); +static void steal_internal(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling); +static bool is_sibling_left_side(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling); + +bool BPTree_delete(BPTreeNode *root, uint64_t key) { + return _BPTree_delete(root, key, NULL); +} + +static bool _BPTree_delete(BPTreeNode *root, uint64_t key, BPTreeNode *parent) { + if (!root->is_leaf && !_BPTree_delete(traverse(root, key), key, root)) { + return false; + } + + int index; + bool is_found = IntegerArray_binary_search(root->keys, key, &index); + if (root->is_leaf && !is_found) { + return false; + } -static uint64_t find_smallest_key(BPTreeNode *root) { if (root->is_leaf) { - return root->keys->items[0]; + IntegerArray_delete_at_index(root->keys, index); + IntegerArray_delete_at_index(root->data, index); + } else if (is_found) { + root->keys->items[index] = find_smallest_key(root->children->items[index + 1]); } - return find_smallest_key(root->children->items[0]); + if (parent == NULL && root->keys->size == 0) { + shrink(root); + } + + if (parent != NULL && root->keys->size < root->order) { + deletion_rebalance(root, parent); + } + + return true; } -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; - } +static BPTreeNode *traverse(BPTreeNode *node, uint64_t key) { + int virtual_insertion_index = lower_bound(node->keys, key); + + if (virtual_insertion_index < node->keys->size && node->keys->items[virtual_insertion_index] == key) { + virtual_insertion_index += 1; } - return -1; + return node->children->items[virtual_insertion_index]; } -static bool is_sibling_left_side(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling) { - return find_child_index(parent, sibling) < find_child_index(parent, 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 void shrink(BPTreeNode *root) { @@ -319,154 +346,114 @@ static void shrink(BPTreeNode *root) { BPTreeNode_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 deletion_rebalance(BPTreeNode *node, BPTreeNode *parent) { + BPTreeNode *sibling = find_sibling(parent, node); -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_insert_at_index(node->keys, 0, stealed_key); - IntegerArray_delete_at_index(sibling->keys, sibling->keys->size - 1); - parent->keys->items[child_index - 1] = stealed_key; - - // The data must also be stolen. - IntegerArray_insert_at_index(node->data, 0, sibling->data->items[sibling->data->size - 1]); - IntegerArray_delete_at_index(sibling->data, sibling->data->size - 1); + if (sibling->keys->size == sibling->order) { + if (is_sibling_left_side(parent, node, sibling)) { + merge(parent, sibling, node); + } else { + merge(parent, node, sibling); + } + } else if (node->is_leaf) { + steal_leaf(parent, node, sibling); } else { - uint64_t stealed_key = sibling->keys->items[0]; - IntegerArray_append(node->keys, stealed_key); - IntegerArray_delete_at_index(sibling->keys, 0); - parent->keys->items[child_index] = sibling->keys->items[0]; - - // The data must also be stolen. - IntegerArray_append(node->data, sibling->data->items[0]); - IntegerArray_delete_at_index(sibling->data, 0); + steal_internal(parent, node, sibling); } } -static void _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]); - } +static BPTreeNode *find_sibling(BPTreeNode *parent, BPTreeNode *node) { + int index_in_children = BPTreeNodeArray_search(parent->children, node); - // Merge the keys. - 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 (index_in_children == 0) { + return parent->children->items[1]; } - // Merge the data. - for (int i = secondary_node->data->size - 1; i >= 0; i--) { - IntegerArray_insert_at_index(main_node->data, 0, secondary_node->data->items[i]); + if (index_in_children == parent->children->size - 1) { + return parent->children->items[parent->children->size - 2]; } - // Merge the children. - for (int i = secondary_node->children->size - 1; i >= 0; i--) { - BPTreeNodeArray_insert_at_index(main_node->children, 0, secondary_node->children->items[i]); + if (parent->children->items[index_in_children - 1]->keys->size > parent->order) { + return parent->children->items[index_in_children - 1]; } - IntegerArray_delete_at_index(parent->keys, pivot_index); - BPTreeNodeArray_delete_at_index(parent->children, pivot_index); + if (parent->children->items[index_in_children + 1]->keys->size > parent->order) { + return parent->children->items[index_in_children + 1]; + } - BPTreeNode_destroy(&secondary_node); + return parent->children->items[index_in_children - 1]; } -static void merge(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling) { - int child_index = find_child_index(parent, node); +static void merge(BPTreeNode *parent, BPTreeNode *left_node, BPTreeNode *right_node) { + int index_in_children = BPTreeNodeArray_search(parent->children, left_node); - if (is_sibling_left_side(parent, node, sibling)) { - _merge(parent, node, sibling, child_index - 1); - } else { - _merge(parent, sibling, node, child_index); + if (!right_node->is_leaf) { + IntegerArray_insert_at_index(right_node->keys, 0, parent->keys->items[index_in_children]); } -} -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]; + // Merge the keys. + for (int i = left_node->keys->size - 1; i >= 0; i--) { + IntegerArray_insert_at_index(right_node->keys, 0, left_node->keys->items[i]); } - if (child_index == parent->children->size - 1) { - return parent->children->items[parent->children->size - 2]; + // Merge the data. + for (int i = left_node->data->size - 1; i >= 0; i--) { + IntegerArray_insert_at_index(right_node->data, 0, left_node->data->items[i]); } - if (parent->children->items[child_index - 1]->keys->size > parent->order) { - return parent->children->items[child_index - 1]; + // Merge the children. + for (int i = left_node->children->size - 1; i >= 0; i--) { + BPTreeNodeArray_insert_at_index(right_node->children, 0, left_node->children->items[i]); } - if (parent->children->items[child_index + 1]->keys->size > parent->order) { - return parent->children->items[child_index + 1]; - } + IntegerArray_delete_at_index(parent->keys, index_in_children); + BPTreeNodeArray_delete_at_index(parent->children, index_in_children); - return parent->children->items[child_index - 1]; + BPTreeNode_destroy(&left_node); } -static BPTreeNode *traverse(BPTreeNode *root, uint64_t key) { - int virtual_insertion_index = lower_bound(root->keys, key); +static void steal_leaf(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling) { + int index_in_children = BPTreeNodeArray_search(parent->children, node); - if (virtual_insertion_index < root->keys->size && root->keys->items[virtual_insertion_index] == key) { - virtual_insertion_index += 1; - } - - return root->children->items[virtual_insertion_index]; -} - -static void deletion_rebalance(BPTreeNode *root, BPTreeNode *parent) { - int child_index = find_child_index(parent, root); - BPTreeNode *sibling = find_sibling(parent, root); + if (is_sibling_left_side(parent, node, sibling)) { + uint64_t stealed_key = sibling->keys->items[sibling->keys->size - 1]; + IntegerArray_insert_at_index(node->keys, 0, stealed_key); + IntegerArray_delete_at_index(sibling->keys, sibling->keys->size - 1); + parent->keys->items[index_in_children - 1] = stealed_key; - if (sibling->keys->size == sibling->order) { - merge(parent, root, sibling); - } else if (root->is_leaf) { - steal_leaf(parent, root, child_index, sibling); + // The data must also be stolen. + IntegerArray_insert_at_index(node->data, 0, sibling->data->items[sibling->data->size - 1]); + IntegerArray_delete_at_index(sibling->data, sibling->data->size - 1); } else { - steal_internal(parent, root, child_index, sibling); - } -} - -static bool _BPTree_delete(BPTreeNode *root, uint64_t key, BPTreeNode *parent) { - if (!root->is_leaf && !_BPTree_delete(traverse(root, key), key, root)) { - return false; - } + uint64_t stealed_key = sibling->keys->items[0]; + IntegerArray_append(node->keys, stealed_key); + IntegerArray_delete_at_index(sibling->keys, 0); + parent->keys->items[index_in_children] = sibling->keys->items[0]; - int index; - bool is_found = IntegerArray_binary_search(root->keys, key, &index); - if (root->is_leaf && !is_found) { - return false; + // The data must also be stolen. + IntegerArray_append(node->data, sibling->data->items[0]); + IntegerArray_delete_at_index(sibling->data, 0); } +} - if (root->is_leaf) { - IntegerArray_delete_at_index(root->keys, index); - IntegerArray_delete_at_index(root->data, index); - } else if (is_found) { - root->keys->items[index] = find_smallest_key(root->children->items[index + 1]); - } +static void steal_internal(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling) { + int index_in_children = BPTreeNodeArray_search(parent->children, node); - if (parent == NULL && root->keys->size == 0) { - shrink(root); - } - - if (parent != NULL && root->keys->size < root->order) { - deletion_rebalance(root, parent); + if (is_sibling_left_side(parent, node, sibling)) { + IntegerArray_insert_at_index(node->keys, 0, parent->keys->items[index_in_children - 1]); + parent->keys->items[index_in_children - 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[index_in_children]); + parent->keys->items[index_in_children] = 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); } - - return true; } -bool BPTree_delete(BPTreeNode *root, uint64_t key) { - return _BPTree_delete(root, key, NULL); +static bool is_sibling_left_side(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling) { + return BPTreeNodeArray_search(parent->children, sibling) < BPTreeNodeArray_search(parent->children, node); }