diff --git a/__main__.py b/__main__.py deleted file mode 100644 index 3e10ac664f0ec2e8ee7d2a71411923985a8fcc98..0000000000000000000000000000000000000000 --- a/__main__.py +++ /dev/null @@ -1,491 +0,0 @@ -import random - - -def lower_bound(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 low - - -def is_value_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 True - - 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 sorted_array_insert(array, value): - index = lower_bound(array, value) - array.insert(index, value) - return index - - -def sorted_array_delete(array, value): - index = find_value_index_in_array(array, value) - array.pop(index) - return index - - -# B+ Tree : START - - -class Node: - def __init__(self, order): - self.order = order - self.is_leaf = True - self.keys = [] - self.children = [] - - -def node_is_full(node): - return len(node.keys) == 2 * node.order - - -# INSERTION : START - - -def redistribute_keys(left_node, right_node, left_index, right_index): - for i in range(right_index, len(left_node.keys)): - right_node.keys.append(left_node.keys[i]) - - for i in range(left_index, len(left_node.keys)): - left_node.keys.pop() - - -def split_leaf(node, key): - virtual_insertion_index = lower_bound(node.keys, key) - median_index = len(node.keys) // 2 - right_node = Node(node.order) - - if virtual_insertion_index < median_index: - median_value = node.keys[median_index - 1] - redistribute_keys(node, right_node, median_index - 1, median_index - 1) - 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) - sorted_array_insert(right_node.keys, key) - else: - median_value = key - redistribute_keys(node, right_node, median_index, median_index) - 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. - node.children.append(right_node) - else: - # The node already has a link to the next node, the right node is linked to it and the node is linked to the right node. - right_node.children.append(node.children[0]) - node.children[0] = right_node - - return median_value, right_node - - -def redistribute_children(left_node, right_node, left_index, right_index): - right_node.children = left_node.children[right_index:] - left_node.children = left_node.children[:left_index] - - -def split_internal(node, key, right_child_node): - virtual_insertion_index = lower_bound(node.keys, key) - median_index = len(node.keys) // 2 - right_node = Node(node.order) - right_node.is_leaf = False - - if virtual_insertion_index < median_index: - # The key is virtually inserted to the left of the median index. - 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 = 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 = 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. - median_value = key - redistribute_keys(node, right_node, median_index, median_index) - redistribute_children(node, right_node, median_index + 1, median_index + 1) - right_node.children.insert(0, right_child_node) - - return median_value, 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 - left_node.children = root.children - root.is_leaf = False - root.keys = [median_value] - root.children = [left_node, split_right_node] - - -def insert_full(root, parents, node, key, previous_split_right_node): - if node.is_leaf: - median_value, split_right_node = split_leaf(node, key) - else: - median_value, split_right_node = split_internal(node, key, previous_split_right_node) - - if node == root: - bptree_grow(root, median_value, split_right_node) - else: - parent = parents.pop() - - if node_is_full(parent): - insert_full(root, parents, parent, median_value, split_right_node) - else: - insert_non_full(parent, median_value, split_right_node) - - -def insert_non_full(node, key, previous_split_right_node): - 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) - - -def insertion_find_leaf(root, key): - parents = [] - current = root - - while not current.is_leaf: - parents.append(current) - children_index = lower_bound(current.keys, key) - current = current.children[children_index] - - return parents, current - - -def bptree_insert(root, key): - parents, leaf = insertion_find_leaf(root, key) - - if is_value_in_array(leaf.keys, key): - return - - 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_find_smallest_key(root): - if root.is_leaf: - return root.keys[0] - - 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() - root.children = child.children.copy() - root.is_leaf = child.is_leaf - - -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): - 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) - - for i in reversed(range(len(secondary_node.keys))): - main_node.keys.insert(0, secondary_node.keys[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]) - - parent.keys.pop(pivot_index) - parent.children.pop(pivot_index) - - -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) - else: - # The node is merged into the sibling. - _bptree_merge(parent, sibling, node, child_index) - - -def find_child_index(parent, child): - for i in range(len(parent.children)): - if child == parent.children[i]: - return i - - return None - - -def bptree_find_sibling(parent, node): - child_index = find_child_index(parent, node) - - if child_index == 0: - # Must take the sibling on the right. - return parent.children[1] - if child_index == len(parent.children) - 1: - # Must take the sibling on the left. - 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. - 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): - parent = None - - if len(parents) > 0: - parent = parents.pop() - - if node.is_leaf: - sorted_array_delete(node.keys, key) - - 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, sibling) - - 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: - bptree_steal_internal(parent, node, child_index, sibling) - - 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) - - -def deletion_find_leaf(root, key): - parents = [] - current = root - - while not current.is_leaf: - parents.append(current) - children_index = lower_bound(current.keys, key) - - if children_index < len(current.keys) and current.keys[children_index] == key: - children_index += 1 - - current = current.children[children_index] - - return parents, current - - -def bptree_delete(root, key): - parents, leaf = deletion_find_leaf(root, key) - - if not is_value_in_array(leaf.keys, key): - return - - _bptree_delete(root, parents, leaf, key) - - -# DELETION : END - - -def bptree_search(root, key): - if root.is_leaf: - return is_value_in_array(root.keys, key) - - children_index = lower_bound(root.keys, key) - - if children_index < len(root.keys) and root.keys[children_index] == key: - children_index += 1 - - return bptree_search(root.children[children_index], key) - - -def bptree_print(root, depth=0): - print(" " * depth, end="") - print(root.keys) - - if root.is_leaf: - return - - for child in root.children: - bptree_print(child, depth + 1) - - -def bptree_extract_all_keys(root): - current = root - - while not current.is_leaf: - current = current.children[0] - - keys = [] - - while current.children: - keys += current.keys - current = current.children[0] - - keys += current.keys - return keys - - -# B+ Tree : END - - -def generate_random_keys(length, min_key, max_key): - keys = [] - - for _ in range(length): - while True: - random_key = random.randint(min_key, max_key) - - if random_key not in keys: - keys.append(random_key) - break - - return keys - - -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) - - # bptree_print(root) - # extracted_keys = bptree_extract_all_keys(root) - # assert extracted_keys == sorted(keys) - - # for key in keys: - # assert bptree_search(root, key) - - # for _ in range(5): - # while True: - # random_key = random.randint(1, 99) - - # if random_key not in keys: - # break - - # assert not bptree_search(root, random_key) - - # ===================================================================== - - root = Node(order) - keys = generate_random_keys(30, 1, 99) - print(keys) - - for key in keys: - bptree_insert(root, key) - - 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__": - main() diff --git a/b.c b/b.c deleted file mode 100644 index c06cf8fb51c83a64ad2f25512fc841cd0f1f772c..0000000000000000000000000000000000000000 --- a/b.c +++ /dev/null @@ -1,57 +0,0 @@ -#include <assert.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> - -#include "BPTree.h" - -int main() { - BPTreeNode *root = BPTree_init(2); - - uint64_t input[] = {8, 12, 11, 47, 22, 95, 86, 40, 33, 78, 28, 5, 75, 88, 21, 56, 82, 51, 93, 66, 48, 70, 57, 65, 35, 4, 60, 41, 49, 55, 68, 72, 23, 31, 30, 42, 18, 87, 24, 58}; - IntegerArray *keys = IntegerArray_init(40); - for (int i = 0; i < 30; i++) { - IntegerArray_append(keys, input[i]); - } - - IntegerArray_print(keys); - - for (int i = 0; i < keys->size; i++) { - BPTree_insert(root, keys->items[i], keys->items[i] * 1000); - } - - for (int i = 0; i < keys->size; i++) { - uint64_t data; - bool found = BPTree_search(root, keys->items[i], &data); - - assert(found == true); - assert(data == keys->items[i] * 1000); - } - - BPTree_delete(root, 65); - BPTree_delete(root, 57); - BPTree_delete(root, 47); - BPTree_delete(root, 28); - BPTree_delete(root, 51); - BPTree_insert(root, 100, 100 * 1000); - BPTree_delete(root, 48); - BPTree_delete(root, 41); - BPTree_delete(root, 60); - BPTree_delete(root, 5); - BPTree_delete(root, 8); - BPTree_delete(root, 21); - - BPTree_delete(root, 86); - BPTree_delete(root, 100); - BPTree_delete(root, 88); - BPTree_delete(root, 95); - BPTree_delete(root, 49); - BPTree_delete(root, 56); - BPTree_delete(root, 55); - - BPTree_print(root, 0); - - IntegerArray_destroy(&keys); - BPTree_destroy(&root); - return EXIT_SUCCESS; -} diff --git a/src/Array.c b/src/Array.c index 81d834904e256aa23f61d6318319280349605cd5..147a52947ded653faa6b4646a90072d1fda94537 100644 --- a/src/Array.c +++ b/src/Array.c @@ -39,14 +39,7 @@ void IntegerArray_destroy(IntegerArray **array) { int IntegerArray_insert_sorted(IntegerArray *array, uint64_t item) { int index = lower_bound(array, item); - // TODO : use IntegerArray_insert_at_index - - for (int i = array->size - 1; i >= index; i--) { - array->items[i + 1] = array->items[i]; - } - - array->items[index] = item; - array->size++; + IntegerArray_insert_at_index(array, index, item); return index; } diff --git a/src/BPTree.c b/src/BPTree.c index 67da7a471c878714cd48757327806bd0db130a1f..ae2fd657b44c073a6c838a477175350d61d7a0d9 100644 --- a/src/BPTree.c +++ b/src/BPTree.c @@ -104,13 +104,17 @@ bool BPTree_search(BPTreeNode *root, uint64_t key, uint64_t *data) { // 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); -static uint64_t split_internal(BPTreeNode *node, uint64_t key, BPTreeNode *right_child_node, BPTreeNode **right_node); -static uint64_t split_leaf(BPTreeNode *node, uint64_t key, uint64_t data, BPTreeNode **right_node); -static void grow(BPTreeNode *root, uint64_t median_value, BPTreeNode *split_right_node); -static void insert_full(BPTreeNode *root, BPTreeNodeArray *parents, BPTreeNode *node, uint64_t key, uint64_t data, BPTreeNode *previous_split_right_node); -static void insert_non_full(BPTreeNode *node, uint64_t key, uint64_t data, BPTreeNode *previous_split_right_node); +static void insert_non_full(BPTreeNode *node, uint64_t key, uint64_t data, BPTreeNode *previous_split_right_node) { + int insertion_index = IntegerArray_insert_sorted(node->keys, key); + + if (node->is_leaf) { + IntegerArray_insert_at_index(node->data, insertion_index, data); + } + + if (previous_split_right_node != NULL) { + BPTreeNodeArray_insert_at_index(node->children, insertion_index + 1, previous_split_right_node); + } +} static void redistribute_keys(BPTreeNode *left_node, BPTreeNode *right_node, int left_index, int right_index) { for (int i = right_index; i < left_node->keys->size; i++) { @@ -128,71 +132,71 @@ static void redistribute_keys(BPTreeNode *left_node, BPTreeNode *right_node, int } } -static void redistribute_children(BPTreeNode *left_node, BPTreeNode *right_node, int left_index, int right_index) { - for (int i = right_index; i < left_node->children->size; i++) { - BPTreeNodeArray_append(right_node->children, left_node->children->items[i]); - } - - left_node->children->size = left_index; -} - -static uint64_t split_internal(BPTreeNode *node, uint64_t key, BPTreeNode *right_child_node, BPTreeNode **right_node) { +static uint64_t split_leaf(BPTreeNode *node, uint64_t key, uint64_t data, BPTreeNode **right_node) { int virtual_insertion_index = lower_bound(node->keys, key); int median_index = node->keys->size / 2; uint64_t median_value; *right_node = BPTree_init(node->order); - (*right_node)->is_leaf = false; if (virtual_insertion_index < median_index) { median_value = node->keys->items[median_index - 1]; - redistribute_keys(node, *right_node, median_index - 1, median_index); - redistribute_children(node, *right_node, median_index, median_index); + redistribute_keys(node, *right_node, median_index - 1, median_index - 1); int insertion_index = IntegerArray_insert_sorted(node->keys, key); - BPTreeNodeArray_insert_at_index(node->children, insertion_index + 1, right_child_node); + IntegerArray_insert_at_index(node->data, insertion_index, data); } else if (virtual_insertion_index > median_index) { median_value = node->keys->items[median_index]; - redistribute_keys(node, *right_node, median_index, median_index + 1); - redistribute_children(node, *right_node, median_index + 1, median_index + 1); + redistribute_keys(node, *right_node, median_index, median_index); int insertion_index = IntegerArray_insert_sorted((*right_node)->keys, key); - BPTreeNodeArray_insert_at_index((*right_node)->children, insertion_index + 1, right_child_node); + IntegerArray_insert_at_index((*right_node)->data, insertion_index, data); } else { median_value = key; redistribute_keys(node, *right_node, median_index, median_index); - redistribute_children(node, *right_node, median_index + 1, median_index + 1); - BPTreeNodeArray_insert_at_index((*right_node)->children, 0, right_child_node); + int insertion_index = IntegerArray_insert_sorted((*right_node)->keys, key); + IntegerArray_insert_at_index((*right_node)->data, insertion_index, data); } + if (node->next != NULL) { + (*right_node)->next = node->next; + } + + node->next = *right_node; return median_value; } -static uint64_t split_leaf(BPTreeNode *node, uint64_t key, uint64_t data, BPTreeNode **right_node) { +static void redistribute_children(BPTreeNode *left_node, BPTreeNode *right_node, int left_index, int right_index) { + for (int i = right_index; i < left_node->children->size; i++) { + BPTreeNodeArray_append(right_node->children, left_node->children->items[i]); + } + + left_node->children->size = left_index; +} + +static uint64_t split_internal(BPTreeNode *node, uint64_t key, BPTreeNode *right_child_node, BPTreeNode **right_node) { int virtual_insertion_index = lower_bound(node->keys, key); int median_index = node->keys->size / 2; uint64_t median_value; *right_node = BPTree_init(node->order); + (*right_node)->is_leaf = false; if (virtual_insertion_index < median_index) { median_value = node->keys->items[median_index - 1]; - redistribute_keys(node, *right_node, median_index - 1, median_index - 1); + redistribute_keys(node, *right_node, median_index - 1, median_index); + redistribute_children(node, *right_node, median_index, median_index); int insertion_index = IntegerArray_insert_sorted(node->keys, key); - IntegerArray_insert_at_index(node->data, insertion_index, data); + BPTreeNodeArray_insert_at_index(node->children, insertion_index + 1, right_child_node); } else if (virtual_insertion_index > median_index) { median_value = node->keys->items[median_index]; - redistribute_keys(node, *right_node, median_index, median_index); + redistribute_keys(node, *right_node, median_index, median_index + 1); + redistribute_children(node, *right_node, median_index + 1, median_index + 1); int insertion_index = IntegerArray_insert_sorted((*right_node)->keys, key); - IntegerArray_insert_at_index((*right_node)->data, insertion_index, data); + BPTreeNodeArray_insert_at_index((*right_node)->children, insertion_index + 1, right_child_node); } else { median_value = key; redistribute_keys(node, *right_node, median_index, median_index); - int insertion_index = IntegerArray_insert_sorted((*right_node)->keys, key); - IntegerArray_insert_at_index((*right_node)->data, insertion_index, data); - } - - if (node->next != NULL) { - (*right_node)->next = node->next; + redistribute_children(node, *right_node, median_index + 1, median_index + 1); + BPTreeNodeArray_insert_at_index((*right_node)->children, 0, right_child_node); } - node->next = *right_node; return median_value; } @@ -238,18 +242,6 @@ static void insert_full(BPTreeNode *root, BPTreeNodeArray *parents, BPTreeNode * } } -static void insert_non_full(BPTreeNode *node, uint64_t key, uint64_t data, BPTreeNode *previous_split_right_node) { - int insertion_index = IntegerArray_insert_sorted(node->keys, key); - - if (node->is_leaf) { - IntegerArray_insert_at_index(node->data, insertion_index, data); - } - - if (previous_split_right_node != NULL) { - BPTreeNodeArray_insert_at_index(node->children, insertion_index + 1, previous_split_right_node); - } -} - void BPTree_insert(BPTreeNode *root, uint64_t key, uint64_t data) { BPTreeNodeArray *parents; BPTreeNode *leaf = find_leaf(root, key, &parents); @@ -271,50 +263,6 @@ void BPTree_insert(BPTreeNode *root, uint64_t key, uint64_t data) { // 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 void shrink(BPTreeNode *root); -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; - } - - 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]); - } - - if (parent == NULL && !root->is_leaf && root->keys->size == 0) { - shrink(root); - } - - if (parent != NULL && root->keys->size < root->order) { - deletion_rebalance(root, parent); - } - - return true; -} - static BPTreeNode *traverse(BPTreeNode *node, uint64_t key) { int virtual_insertion_index = lower_bound(node->keys, key); @@ -346,22 +294,6 @@ static void shrink(BPTreeNode *root) { BPTreeNode_destroy(&child); } -static void deletion_rebalance(BPTreeNode *node, BPTreeNode *parent) { - BPTreeNode *sibling = find_sibling(parent, node); - - 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 { - steal_internal(parent, node, sibling); - } -} - static BPTreeNode *find_sibling(BPTreeNode *parent, BPTreeNode *node) { int index_in_children = BPTreeNodeArray_search(parent->children, node); @@ -384,6 +316,10 @@ static BPTreeNode *find_sibling(BPTreeNode *parent, BPTreeNode *node) { return parent->children->items[index_in_children - 1]; } +static bool is_sibling_left_side(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling) { + return BPTreeNodeArray_search(parent->children, sibling) < BPTreeNodeArray_search(parent->children, node); +} + static void merge(BPTreeNode *parent, BPTreeNode *left_node, BPTreeNode *right_node) { int index_in_children = BPTreeNodeArray_search(parent->children, left_node); @@ -454,6 +390,51 @@ static void steal_internal(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sib } } -static bool is_sibling_left_side(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sibling) { - return BPTreeNodeArray_search(parent->children, sibling) < BPTreeNodeArray_search(parent->children, node); +static void deletion_rebalance(BPTreeNode *node, BPTreeNode *parent) { + BPTreeNode *sibling = find_sibling(parent, node); + + 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 { + steal_internal(parent, node, 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; + } + + int index; + bool is_found = IntegerArray_binary_search(root->keys, key, &index); + if (root->is_leaf && !is_found) { + return false; + } + + 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]); + } + + if (parent == NULL && !root->is_leaf && root->keys->size == 0) { + shrink(root); + } + + if (parent != NULL && root->keys->size < root->order) { + deletion_rebalance(root, parent); + } + + return true; +} + +bool BPTree_delete(BPTreeNode *root, uint64_t key) { + return _BPTree_delete(root, key, NULL); } diff --git a/src/BPTree.h b/src/BPTree.h index 74fb34e299448c7f6269a4f3913538e2db45dc5d..0c6bcb7297068d1ba4782e29c2fc90156b525757 100644 --- a/src/BPTree.h +++ b/src/BPTree.h @@ -20,13 +20,7 @@ void BPTree_destroy(BPTreeNode **root); void BPTree_print(BPTreeNode *root, int depth); bool BPTree_search(BPTreeNode *root, uint64_t key, uint64_t *data); - -// Insertion - void BPTree_insert(BPTreeNode *root, uint64_t key, uint64_t data); - -// Deletion - bool BPTree_delete(BPTreeNode *root, uint64_t key); #endif diff --git a/src/DirectoryRecord.h b/src/DirectoryRecord.h index 9c923dd2ce66be257470564b6eb6c4e331ed8d2a..9f148ab77c21d5921da9055be41a0b64507e8f84 100644 --- a/src/DirectoryRecord.h +++ b/src/DirectoryRecord.h @@ -31,6 +31,7 @@ int DirectoryRecord_size_on_disk(); DirectoryRecord *DirectoryRecord_init(bool is_deleted, char phone_number[PHONE_NUMBER_MAX_LENGTH], char name[NAME_MAX_LENGTH], char surname[SURNAME_MAX_LENGTH], int birth_date_year, int birth_date_month, int birth_date_day); void DirectoryRecord_destroy(DirectoryRecord **record); + void DirectoryRecord_print(DirectoryRecord *record); ByteArray *DirectoryRecord_to_ByteArray(DirectoryRecord *record); DirectoryRecord *ByteArray_to_DirectoryRecord(ByteArray* byte_array); diff --git a/src/main.c b/src/main.c index a361faf74b42b8d924c80858edc0ce1acfc36f19..817db1ef3cdbb7045e9fa3d23d4c71098dd2d689 100644 --- a/src/main.c +++ b/src/main.c @@ -1,4 +1,4 @@ -// CAUTION : validation des entrées +// TODO : replace 11 with pseudo variable #include <stdio.h> #include <stdlib.h> @@ -14,25 +14,26 @@ void clear_buffer() { void append_record(Directory *directory) { char phone_number[11]; printf("Enter the phone number: "); - scanf("%s", phone_number); + scanf("%10s", phone_number); clear_buffer(); char name[21]; printf("Enter the name: "); - scanf("%s", name); + scanf("%20s", name); clear_buffer(); char surname[21]; printf("Enter the surname: "); - scanf("%s", surname); + scanf("%20s", surname); clear_buffer(); - printf("Enter the birth date (Y-m-d): "); - // TODO : check more int birth_date_year, birth_date_month, birth_date_day; - scanf("%d-%d-%d", &birth_date_year, &birth_date_month, &birth_date_day); - clear_buffer(); + do + { + printf("Enter the birth date (Y-m-d): "); + } while (scanf("%d-%d-%d", &birth_date_year, &birth_date_month, &birth_date_day) != 3); + clear_buffer(); printf("\nIs the information entered correct? (Y/n) "); char choice = getchar(); @@ -57,9 +58,8 @@ void append_record(Directory *directory) { void search_record(Directory *directory) { printf("Enter the phone number that corresponds to the record you are looking for: "); - // TODO : crash phone number overflow char phone_number[11]; - scanf("%s", phone_number); + scanf("%10s", phone_number); clear_buffer(); DirectoryRecord *record = Directory_search(directory, phone_number); printf("\n"); @@ -78,7 +78,7 @@ void delete_record(Directory *directory) { printf("Enter the phone number that corresponds to the record you wish to delete: "); char phone_number[11]; - scanf("%s", phone_number); + scanf("%10s", phone_number); clear_buffer(); DirectoryRecord *record = Directory_search(directory, phone_number); printf("\n"); diff --git a/src/tests/BPTreeTests.c b/src/tests/BPTreeTests.c index 06a1249b06fa437f5d2130a2b83586dd8650e74e..54ba8e30fa6342217f8da7dff7935577fc640ab3 100644 --- a/src/tests/BPTreeTests.c +++ b/src/tests/BPTreeTests.c @@ -23,39 +23,6 @@ void tearDown(void) { // BEGIN : Compliance with B+ Tree rules -static bool check_if_BPTree_is_compliant_with_the_rules(BPTreeNode *root); -static bool check_if_the_leaves_are_all_at_the_same_depth(BPTreeNode *root); -static int compute_first_leaf_depth(BPTreeNode *root); -static bool _check_if_the_leaves_are_all_at_the_same_depth(BPTreeNode *root, int expected_depth, int depth); -static bool check_if_all_internal_nodes_have_no_data(BPTreeNode *root); -static bool check_if_all_leaf_nodes_have_as_much_data_as_keys(BPTreeNode *root); -static bool check_if_the_keys_are_sorted_in_all_nodes(BPTreeNode *root); -static bool check_if_the_array_is_sorted(IntegerArray *array); -static bool check_if_all_nodes_except_the_root_have_not_less_keys_than_the_minimum(BPTreeNode *root, BPTreeNode *parent); -static bool check_if_all_nodes_have_no_more_keys_than_the_maximum(BPTreeNode *root); -static bool check_in_all_internal_nodes_there_is_1_child_more_than_the_number_of_keys(BPTreeNode *root); -static bool check_if_the_keys_are_inserted_in_the_right_place(BPTreeNode *root); -static bool check_if_the_keys_are_inserted_in_the_right_place_with_range(BPTreeNode *root, uint64_t left, uint64_t right); - -static bool check_if_BPTree_is_compliant_with_the_rules(BPTreeNode *root) { - bool is_compliant = true; - is_compliant &= check_if_the_leaves_are_all_at_the_same_depth(root); - is_compliant &= check_if_all_internal_nodes_have_no_data(root); - is_compliant &= check_if_all_leaf_nodes_have_as_much_data_as_keys(root); - is_compliant &= check_if_the_keys_are_sorted_in_all_nodes(root); - is_compliant &= check_if_all_nodes_except_the_root_have_not_less_keys_than_the_minimum(root, NULL); - is_compliant &= check_if_all_nodes_have_no_more_keys_than_the_maximum(root); - is_compliant &= check_in_all_internal_nodes_there_is_1_child_more_than_the_number_of_keys(root); - is_compliant &= check_if_the_keys_are_inserted_in_the_right_place(root); - // TODO : check if linked list is ok - return is_compliant; -} - -static bool check_if_the_leaves_are_all_at_the_same_depth(BPTreeNode *root) { - int expected_depth = compute_first_leaf_depth(root); - return _check_if_the_leaves_are_all_at_the_same_depth(root, expected_depth, 0); -} - static int compute_first_leaf_depth(BPTreeNode *root) { if (root->is_leaf) { return 0; @@ -64,13 +31,13 @@ static int compute_first_leaf_depth(BPTreeNode *root) { return compute_first_leaf_depth(root->children->items[0]) + 1; } -static bool _check_if_the_leaves_are_all_at_the_same_depth(BPTreeNode *root, int expected_depth, int depth) { +static bool check_if_the_leaves_are_all_at_the_same_depth(BPTreeNode *root, int expected_depth, int depth) { if (root->is_leaf) { return depth == expected_depth; } for (int i = 0; i < root->children->size; i++) { - if (!_check_if_the_leaves_are_all_at_the_same_depth(root->children->items[i], expected_depth, depth + 1)) { + if (!check_if_the_leaves_are_all_at_the_same_depth(root->children->items[i], expected_depth, depth + 1)) { return false; } } @@ -106,24 +73,24 @@ static bool check_if_all_leaf_nodes_have_as_much_data_as_keys(BPTreeNode *root) return true; } -static bool check_if_the_keys_are_sorted_in_all_nodes(BPTreeNode *root) { - for (int i = 0; i < root->children->size; i++) { - if (!check_if_the_keys_are_sorted_in_all_nodes(root->children->items[i])) { +static bool check_if_the_array_is_sorted(IntegerArray *array) { + for (int i = 0; i < array->size - 1; i++) { + if (array->items[i] > array->items[i + 1]) { return false; } } - return check_if_the_array_is_sorted(root->keys); + return true; } -static bool check_if_the_array_is_sorted(IntegerArray *array) { - for (int i = 0; i < array->size - 1; i++) { - if (array->items[i] > array->items[i + 1]) { +static bool check_if_the_keys_are_sorted_in_all_nodes(BPTreeNode *root) { + for (int i = 0; i < root->children->size; i++) { + if (!check_if_the_keys_are_sorted_in_all_nodes(root->children->items[i])) { return false; } } - return true; + return check_if_the_array_is_sorted(root->keys); } static bool check_if_all_nodes_except_the_root_have_not_less_keys_than_the_minimum(BPTreeNode *root, BPTreeNode *parent) { @@ -164,6 +131,22 @@ static bool check_in_all_internal_nodes_there_is_1_child_more_than_the_number_of return root->children->size == root->keys->size + 1; } +static bool check_if_the_keys_are_inserted_in_the_right_place_with_range(BPTreeNode *root, uint64_t left, uint64_t right) { + for (int i = 0; i < root->keys->size; i++) { + if (root->keys->items[i] < left || root->keys->items[i] >= right) { + return false; + } + } + + for (int i = 0; i < root->children->size; i++) { + if (!check_if_the_keys_are_inserted_in_the_right_place_with_range(root->children->items[i], left, right)) { + return false; + } + } + + return true; +} + static bool check_if_the_keys_are_inserted_in_the_right_place(BPTreeNode *root) { if (root->is_leaf) { return true; @@ -194,20 +177,18 @@ static bool check_if_the_keys_are_inserted_in_the_right_place(BPTreeNode *root) return true; } -static bool check_if_the_keys_are_inserted_in_the_right_place_with_range(BPTreeNode *root, uint64_t left, uint64_t right) { - for (int i = 0; i < root->keys->size; i++) { - if (root->keys->items[i] < left || root->keys->items[i] >= right) { - return false; - } - } - - for (int i = 0; i < root->children->size; i++) { - if (!check_if_the_keys_are_inserted_in_the_right_place_with_range(root->children->items[i], left, right)) { - return false; - } - } - - return true; +static bool check_BPTree_compliance(BPTreeNode *root) { + bool is_compliant = true; + is_compliant &= check_if_the_leaves_are_all_at_the_same_depth(root, compute_first_leaf_depth(root), 0); + is_compliant &= check_if_all_internal_nodes_have_no_data(root); + is_compliant &= check_if_all_leaf_nodes_have_as_much_data_as_keys(root); + is_compliant &= check_if_the_keys_are_sorted_in_all_nodes(root); + is_compliant &= check_if_all_nodes_except_the_root_have_not_less_keys_than_the_minimum(root, NULL); + is_compliant &= check_if_all_nodes_have_no_more_keys_than_the_maximum(root); + is_compliant &= check_in_all_internal_nodes_there_is_1_child_more_than_the_number_of_keys(root); + is_compliant &= check_if_the_keys_are_inserted_in_the_right_place(root); + // TODO : check if linked list is ok + return is_compliant; } // END : BPTree Compliance @@ -279,7 +260,7 @@ static void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_g for (int i = 0; i < keys->size; i++) { BPTree_insert(*root, keys->items[i], transform_key_to_data(keys->items[i])); // After each insertion is verified that the B+ Tree is compliant with the rules. - TEST_ASSERT(check_if_BPTree_is_compliant_with_the_rules(*root)); + TEST_ASSERT(check_BPTree_compliance(*root)); } IntegerArray_destroy(&keys);