From 3c8c33b47aa76ed8677c0abd372580972c724999 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Tue, 24 Jan 2023 12:07:30 +0100 Subject: [PATCH] fix(heap): some insert fixes --- src/heap/vieter_heap.c | 39 +++++++++++++++---- src/heap/vieter_heap_tree.c | 76 +++++++++++++++++++++++++++++-------- src/heap/vieter_heap_tree.h | 11 +++++- test/heap/test_heap.c | 39 +++++++++++++++++-- 4 files changed, 135 insertions(+), 30 deletions(-) diff --git a/src/heap/vieter_heap.c b/src/heap/vieter_heap.c index ceecdbb..8e036b6 100644 --- a/src/heap/vieter_heap.c +++ b/src/heap/vieter_heap.c @@ -14,7 +14,7 @@ uint64_t vieter_heap_size(vieter_heap *heap) { vieter_heap_tree *tree = heap->tree; while (tree != NULL) { - size |= 1 << tree->order; + size |= (uint64_t)1 << tree->order; tree = tree->next; } @@ -22,14 +22,25 @@ uint64_t vieter_heap_size(vieter_heap *heap) { return size; } -void vieter_heap_free(vieter_heap *heap) {} +void vieter_heap_free(vieter_heap *heap) { + vieter_heap_tree *tree = heap->tree; + vieter_heap_tree *next; + + while (tree != NULL) { + next = tree->next; + vieter_heap_tree_free(tree); + tree = next; + } + + free(heap); +} vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key, void *data) { vieter_heap_node *new_node = vieter_heap_node_init(); new_node->key = key; new_node->data = data; - vieter_heap_tree *new_tree = vieter_heap_tree_init(new_node, NULL, 1); + vieter_heap_tree *new_tree = vieter_heap_tree_init(new_node, NULL, 0); if (heap->tree == NULL) { heap->tree = new_tree; @@ -41,6 +52,18 @@ vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key, } vieter_heap_error vieter_heap_pop(void **out, vieter_heap *heap) { + if (heap->tree == NULL) { + return vieter_heap_empty; + } + + if (heap->tree->order == 0) { + *out = heap->tree->root->data; + vieter_heap_tree_free(heap->tree); + heap->tree = NULL; + + return vieter_heap_ok; + } + return vieter_heap_ok; } @@ -49,17 +72,17 @@ vieter_heap_error vieter_heap_peek(void **out, vieter_heap *heap) { return vieter_heap_empty; } - uint64_t smallest_key; - vieter_heap_tree *tree = heap->tree; + uint64_t smallest_key = tree->root->key; + *out = tree->root->data; + + while (tree->next != NULL) { + tree = tree->next; - while (tree != NULL) { if (tree->root->key < smallest_key) { smallest_key = tree->root->key; *out = tree->root->data; } - - tree = tree->next; } return vieter_heap_ok; diff --git a/src/heap/vieter_heap_tree.c b/src/heap/vieter_heap_tree.c index b3e3d1e..8dcc29b 100644 --- a/src/heap/vieter_heap_tree.c +++ b/src/heap/vieter_heap_tree.c @@ -4,9 +4,39 @@ vieter_heap_node *vieter_heap_node_init() { return calloc(1, sizeof(vieter_heap_node)); } +void vieter_heap_node_free(vieter_heap_node *node) { free(node); } + +void vieter_heap_tree_free(vieter_heap_tree *tree) { + uint64_t size = 1; + vieter_heap_node **stack = + malloc(((uint64_t)1 << tree->order) * sizeof(vieter_heap_node *)); + stack[0] = tree->root; + + vieter_heap_node *node; + + while (size > 0) { + node = stack[size - 1]; + size--; + + if (node->largest_order != NULL) { + stack[size] = node->largest_order; + size++; + } + + if (node->next_largest_order != NULL) { + stack[size] = node->next_largest_order; + size++; + } + + vieter_heap_node_free(node); + } + + free(stack); + free(tree); +} + vieter_heap_tree *vieter_heap_tree_init(vieter_heap_node *root, - vieter_heap_tree *next, - uint64_t order) { + vieter_heap_tree *next, uint8_t order) { vieter_heap_tree *tree = malloc(sizeof(vieter_heap_tree)); tree->root = root; @@ -54,7 +84,7 @@ vieter_heap_tree *vieter_heap_tree_merge_same_order(vieter_heap_tree *tree_a, vieter_heap_tree *vieter_heap_tree_merge(vieter_heap_tree *tree_a, vieter_heap_tree *tree_b) { - vieter_heap_tree *tree, *target; + vieter_heap_tree *tree, *target, *out; if (tree_a->order <= tree_b->order) { target = tree_a; @@ -67,7 +97,7 @@ vieter_heap_tree *vieter_heap_tree_merge(vieter_heap_tree *tree_a, vieter_heap_tree *next_tree, *next_target; vieter_heap_tree *previous_target = NULL; - while (target != NULL && target != NULL) { + while (target != NULL && tree != NULL) { if (target->order == tree->order) { next_tree = tree->next; next_target = target->next; @@ -76,38 +106,52 @@ vieter_heap_tree *vieter_heap_tree_merge(vieter_heap_tree *tree_a, target->next = next_target; - if (previous_target != NULL) { - previous_target->next = target; - } - - tree = next_tree; - // If this merge produces a binomial tree whose size is already in - // target, it will be the next target. Therefore, we can target's + // target, it will be the next target. Therefore, we can merge target's // trees until we no longer have a duplicate depth. while (target->next != NULL && target->next->order == target->order) { - next_target = target->next; + next_target = target->next->next; target = vieter_heap_tree_merge_same_order(target, target->next); target->next = next_target; } + + if (previous_target != NULL) { + previous_target->next = target; + } else { + out = target; + } + + tree = next_tree; } else if (target->order > tree->order) { + next_tree = tree->next; + if (previous_target == NULL) { previous_target = tree; + out = tree; } else { previous_target->next = tree; } tree->next = target; - - tree = tree->next; + tree = next_tree; } else { + if (previous_target == NULL) { + out = target; + } + previous_target = target; target = target->next; } } // Append final part of tree to target - target->next = tree; + if (target == NULL) { + previous_target->next = tree; + } + + return out; +} + +vieter_heap_tree *vieter_heap_tree_pop(vieter_heap_tree *tree) { - return target; } diff --git a/src/heap/vieter_heap_tree.h b/src/heap/vieter_heap_tree.h index 03b61a4..117e1a9 100644 --- a/src/heap/vieter_heap_tree.h +++ b/src/heap/vieter_heap_tree.h @@ -16,16 +16,23 @@ vieter_heap_node *vieter_heap_node_init(); void vieter_heap_node_free(vieter_heap_node *node); typedef struct vieter_heap_tree { - uint64_t order; + uint8_t order; vieter_heap_node *root; struct vieter_heap_tree *next; } vieter_heap_tree; -vieter_heap_tree *vieter_heap_tree_init(vieter_heap_node *root, vieter_heap_tree *next, uint64_t order); +vieter_heap_tree *vieter_heap_tree_init(vieter_heap_node *root, vieter_heap_tree *next, uint8_t order); + +/* + * Deallocate a tree object, along with its underlying tree structure. + */ +void vieter_heap_tree_free(vieter_heap_tree *tree); vieter_heap_tree *vieter_heap_tree_merge(vieter_heap_tree *tree_a, vieter_heap_tree *tree_b); vieter_heap_tree *vieter_heap_tree_merge_same_order(vieter_heap_tree *tree_a, vieter_heap_tree *tree_b); +vieter_heap_tree *vieter_heap_tree_pop(vieter_heap_tree *tree); + #endif diff --git a/test/heap/test_heap.c b/test/heap/test_heap.c index 7367f28..38d9095 100644 --- a/test/heap/test_heap.c +++ b/test/heap/test_heap.c @@ -28,6 +28,8 @@ void test_merge_same_order() { TEST_CHECK(merged->root->key == 1); TEST_CHECK(merged->root->largest_order == root_b); TEST_CHECK(merged->root->next_largest_order == NULL); + + vieter_heap_tree_free(merged); } void test_insert() { @@ -36,18 +38,47 @@ void test_insert() { void *data; - for (uint64_t i = 50; i <= 0; i--) { + for (uint64_t i = 50; i > 0; i--) { vieter_heap_insert(heap, i, (void *)i); TEST_SIZE(heap, (uint64_t)51 - i); + data = 0; + + TEST_CHECK(vieter_heap_peek(&data, heap) == vieter_heap_ok); + TEST_CHECK_(data == (void *)i, "%lX == %lX", (uint64_t)data, i); + } + + vieter_heap_free(heap); +} + +void test_pop() { + vieter_heap *heap = vieter_heap_init(); + TEST_SIZE(heap, 0); + + void *data; + + for (uint64_t i = 50; i > 0; i--) { + vieter_heap_insert(heap, i, (void *)i); + TEST_SIZE(heap, (uint64_t)50 - i); + TEST_CHECK(vieter_heap_peek(&data, heap) == vieter_heap_ok); TEST_CHECK(data == (void*)i); } + + data = NULL; + + for (uint64_t i = 1; i <= 50; i++) { + TEST_CHECK(vieter_heap_pop(&data, heap) == vieter_heap_ok); + TEST_CHECK(data == (void*)i); + TEST_SIZE(heap, (uint64_t)50 - i); + } + + vieter_heap_free(heap); } TEST_LIST = { - {"test_init", test_init}, - {"test_merge_same_order", test_merge_same_order}, - {"test_insert", test_insert}, + {"init", test_init}, + {"merge same order", test_merge_same_order}, + {"insert", test_insert}, {NULL, NULL} };