From 935a610b7ecf803d24affe357696042b6b3e970f Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Thu, 19 Jan 2023 22:45:22 +0100 Subject: [PATCH] feat(tree): initially working binary tree --- Makefile | 2 +- src/tree/node.c | 125 +++++++++++++++++++++++++++++++---- src/tree/node.h | 11 ++- test/tree/test_binary_tree.c | 21 ++++++ 4 files changed, 141 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 411a033..665c411 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ objs: $(OBJS) .PHONY: vieter vieter: $(LIB) -$(BUILD_DIR)/$(LIB_FILENAME): $(OBJS) +$(LIB): $(OBJS) ar -rcs $@ $(OBJS) $(BUILD_DIR)/$(SRC_DIR)/%.c.o: $(SRC_DIR)/%.c diff --git a/src/tree/node.c b/src/tree/node.c index 935a56d..131e932 100644 --- a/src/tree/node.c +++ b/src/tree/node.c @@ -4,9 +4,35 @@ vieter_tree_node *vieter_tree_node_init() { return calloc(1, sizeof(vieter_tree_node)); } -vieter_tree_error vieter_tree_node_insert(vieter_tree_node *node, uint64_t key, +void vieter_tree_node_add_child(vieter_tree_node *parent, uint64_t key, + vieter_tree_node *child) { + if (parent == NULL) { + return; + } + + if (key < parent->key) { + parent->left = child; + } else { + parent->right = child; + } + + if (child != NULL) { + child->parent = parent; + } +} + +void vieter_tree_node_replace(vieter_tree_node *to_replace, + vieter_tree_node *replacement) { + to_replace->key = replacement->key; + to_replace->data = replacement->data; + to_replace->left = replacement->left; + to_replace->right = replacement->right; +} + +vieter_tree_error vieter_tree_node_insert(vieter_tree_node *root, uint64_t key, void *data) { - vieter_tree_node *parent = node; + vieter_tree_node *node = root; + vieter_tree_node *parent = root; while (node != NULL) { if (node->key == key) { @@ -15,7 +41,7 @@ vieter_tree_error vieter_tree_node_insert(vieter_tree_node *node, uint64_t key, parent = node; - if (key < node->key) { + if (key < parent->key) { node = parent->left; } else { node = parent->right; @@ -25,22 +51,20 @@ vieter_tree_error vieter_tree_node_insert(vieter_tree_node *node, uint64_t key, vieter_tree_node *new_node = vieter_tree_node_init(); new_node->key = key; new_node->data = data; - new_node->parent = parent; - if (key < node->key) { - parent->left = new_node; - } else { - parent->right = new_node; - } + vieter_tree_node_add_child(parent, key, new_node); return vieter_tree_ok; } -vieter_tree_error vieter_tree_node_search(void **out, vieter_tree_node *node, - uint64_t key) { +vieter_tree_error vieter_tree_node_search_node(vieter_tree_node **out, + vieter_tree_node *root, + uint64_t key) { + vieter_tree_node *node = root; + while (node != NULL) { if (node->key == key) { - *out = node->data; + *out = node; return vieter_tree_ok; } @@ -55,7 +79,80 @@ vieter_tree_error vieter_tree_node_search(void **out, vieter_tree_node *node, return vieter_tree_not_present; } -vieter_tree_error vieter_tree_node_remove(void **out, vieter_tree_node *node, +vieter_tree_error vieter_tree_node_search(void **out, vieter_tree_node *root, uint64_t key) { - return vieter_tree_not_present; + vieter_tree_node *target; + vieter_tree_error res = vieter_tree_node_search_node(&target, root, key); + + if (res != vieter_tree_ok) { + return res; + } + + *out = target->data; + + return vieter_tree_ok; +} + +vieter_tree_node *vieter_tree_node_successor(vieter_tree_node *node) { + if ((node->left != NULL) ^ (node->right != NULL)) { + return node->left != NULL ? node->left : node->right; + } + + node = node->right; + + while (node->left != NULL) { + node = node->left; + } + + return node; +} + +vieter_tree_error vieter_tree_node_remove(void **out, vieter_tree_node *root, + uint64_t key) { + vieter_tree_node *target; + vieter_tree_error res = vieter_tree_node_search_node(&target, root, key); + + if (res != vieter_tree_ok) { + return res; + } + + *out = target->data; + + if (target->left == NULL && target->right == NULL) { + vieter_tree_node_add_child(target->parent, target->key, NULL); + + free(target); + } else if ((target->left == NULL) ^ (target->right == NULL)) { + vieter_tree_node *child = + target->left != NULL ? target->left : target->right; + + if (target->parent != NULL) { + vieter_tree_node_add_child(target->parent, child->key, child); + free(target); + } else { + vieter_tree_node_replace(target, child); + free(child); + } + + } else { + vieter_tree_node *replacement = target->right; + + while (replacement->left != NULL) { + replacement = replacement->left; + } + + // We use replacement->key here because the right child can be NULL, so + // reading its key isn't safe. Using replacement->key however, the child + // will still get placed into the right location because of how binary + // trees work. + vieter_tree_node_add_child(replacement->parent, replacement->key, + replacement->right); + + target->key = replacement->key; + target->data = replacement->data; + + free(replacement); + } + + return vieter_tree_ok; } diff --git a/src/tree/node.h b/src/tree/node.h index f22a965..68da70e 100644 --- a/src/tree/node.h +++ b/src/tree/node.h @@ -14,10 +14,15 @@ typedef struct vieter_tree_node { vieter_tree_node *vieter_tree_node_init(); -vieter_tree_error vieter_tree_node_insert(vieter_tree_node *node, uint64_t key, void *data); +vieter_tree_error vieter_tree_node_insert(vieter_tree_node *root, uint64_t key, void *data); -vieter_tree_error vieter_tree_node_search(void **out, vieter_tree_node *node, uint64_t key); +vieter_tree_error vieter_tree_node_search_node(vieter_tree_node **out, vieter_tree_node *root, uint64_t key); +vieter_tree_error vieter_tree_node_search(void **out, vieter_tree_node *root, uint64_t key); -vieter_tree_error vieter_tree_node_remove(void **out, vieter_tree_node *node, uint64_t key); +vieter_tree_error vieter_tree_node_remove(void **out, vieter_tree_node *root, uint64_t key); + +vieter_tree_node *vieter_tree_node_successor(vieter_tree_node *node); + +void vieter_tree_node_replace(vieter_tree_node *to_replace, vieter_tree_node *replacement); #endif diff --git a/test/tree/test_binary_tree.c b/test/tree/test_binary_tree.c index fd6bb1b..4b1ceba 100644 --- a/test/tree/test_binary_tree.c +++ b/test/tree/test_binary_tree.c @@ -17,16 +17,37 @@ void test_insert() { for (uint64_t i = 0; i < 25; i++) { TEST_CHECK(vieter_tree_insert(tree, i, NULL) == vieter_tree_ok); + TEST_SIZE(tree, i + 1); } void *out; for (uint64_t i = 0; i < 25; i++) { + TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_ok); TEST_CHECK(vieter_tree_insert(tree, i, NULL) == vieter_tree_already_present); TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_ok); } } +void test_remove() { + vieter_tree *tree = vieter_tree_init(); + + for (uint64_t i = 0; i < 25; i++) { + TEST_CHECK(vieter_tree_insert(tree, i, NULL) == vieter_tree_ok); + } + + void *out; + + for (uint64_t i = 0; i < 25; i++) { + TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_ok); + TEST_CHECK(vieter_tree_remove(&out, tree, i) == vieter_tree_ok); + TEST_CHECK(vieter_tree_search(&out, tree, i) == vieter_tree_not_present); + } +} + TEST_LIST = { + {"test_init", test_init}, + {"test_insert", test_insert}, + {"test_remove", test_remove}, {NULL, NULL} };