feat(tree): initially working binary tree
							parent
							
								
									98f158e1f5
								
							
						
					
					
						commit
						935a610b7e
					
				
							
								
								
									
										2
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										2
									
								
								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 | ||||
|  |  | |||
							
								
								
									
										125
									
								
								src/tree/node.c
								
								
								
								
							
							
						
						
									
										125
									
								
								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; | ||||
| } | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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} | ||||
| }; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue