From 6845e67cb6af299fdfcce1172c1e132d6ea826a5 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Tue, 24 Jan 2023 19:45:01 +0100 Subject: [PATCH 1/2] feat(heap): possibly working pop --- src/heap/vieter_heap.c | 26 +++++----- src/heap/vieter_heap_tree.c | 95 ++++++++++++++++++------------------- test/heap/test_heap.c | 38 +++++++-------- 3 files changed, 78 insertions(+), 81 deletions(-) diff --git a/src/heap/vieter_heap.c b/src/heap/vieter_heap.c index ae69805..f6d3eab 100644 --- a/src/heap/vieter_heap.c +++ b/src/heap/vieter_heap.c @@ -51,23 +51,23 @@ vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key, return vieter_heap_ok; } -/* vieter_heap_error vieter_heap_pop(void **out, vieter_heap *heap) { */ -/* if (heap->tree == NULL) { */ -/* return vieter_heap_empty; */ -/* } */ +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; */ + if (heap->tree->order == 0 && heap->tree->ptr.next_tree == NULL) { + *out = heap->tree->data; + vieter_heap_tree_free(heap->tree); + heap->tree = NULL; -/* return vieter_heap_ok; */ -/* } */ + return vieter_heap_ok; + } -/* vieter_heap_tree_pop(out, heap->tree); */ + heap->tree = vieter_heap_tree_pop(out, heap->tree); -/* return vieter_heap_ok; */ -/* } */ + return vieter_heap_ok; +} vieter_heap_error vieter_heap_peek(void **out, vieter_heap *heap) { if (heap->tree == NULL) { diff --git a/src/heap/vieter_heap_tree.c b/src/heap/vieter_heap_tree.c index 584ab46..56907a8 100644 --- a/src/heap/vieter_heap_tree.c +++ b/src/heap/vieter_heap_tree.c @@ -41,18 +41,6 @@ end: vieter_heap_node_free(root); } -/* vieter_heap_tree *vieter_heap_tree_init(vieter_heap_node *root, */ -/* vieter_heap_tree *next, uint8_t - * order) { */ -/* vieter_heap_tree *tree = malloc(sizeof(vieter_heap_tree)); */ - -/* tree->root = root; */ -/* tree->next = next; */ -/* tree->order = order; */ - -/* return tree; */ -/* } */ - vieter_heap_node *vieter_heap_tree_merge_same_order(vieter_heap_node *root_a, vieter_heap_node *root_b) { vieter_heap_node *new_root; @@ -144,52 +132,61 @@ vieter_heap_node *vieter_heap_tree_merge(vieter_heap_node *root_a, return out; } -/* vieter_heap_tree *vieter_heap_tree_pop(void **out, vieter_heap_tree *tree) { - */ -/* vieter_heap_tree *tree_before_smallest = NULL; */ -/* vieter_heap_tree *previous_tree = NULL; */ -/* vieter_heap_tree *tree_out = tree; */ +vieter_heap_node *vieter_heap_tree_pop(void **out, vieter_heap_node *tree) { + vieter_heap_node *tree_before_smallest = NULL; + vieter_heap_node *previous_tree = NULL; + vieter_heap_node *original_root = tree; -/* uint64_t smallest_key = tree->root->key; */ + uint64_t smallest_key = tree->key; -/* while (tree->next != NULL) { */ -/* previous_tree = tree; */ -/* tree = tree->next; */ + while (tree->ptr.next_tree != NULL) { + previous_tree = tree; + tree = tree->ptr.next_tree; -/* if (tree->root->key < smallest_key) { */ -/* smallest_key = tree->root->key; */ -/* *out = tree->root->data; */ -/* tree_before_smallest = previous_tree; */ -/* } */ -/* } */ + if (tree->key < smallest_key) { + smallest_key = tree->key; + tree_before_smallest = previous_tree; + } + } -/* if (tree_before_smallest != NULL) { */ -/* previous_tree->next = tree->next; */ -/* } else { */ -/* tree_out = tree_out->next; */ -/* } */ + vieter_heap_node *tree_to_pop; -/* if (tree->order == 0) { */ -/* vieter_heap_tree_free(tree); */ + if (tree_before_smallest != NULL) { + tree_to_pop = tree_before_smallest->ptr.next_tree; + tree_before_smallest->ptr.next_tree = tree_to_pop->ptr.next_tree; + } else { + tree_to_pop = original_root; + original_root = original_root->ptr.next_tree; + } -/* return NULL; */ -/* } */ + *out = tree_to_pop->data; -/* uint8_t old_order = tree->order; */ + if (tree_to_pop->order == 0) { + vieter_heap_tree_free(tree_to_pop); -/* vieter_heap_node *node = tree->root->largest_order; */ -/* free(tree->root); */ + return original_root; + } -/* previous_tree = vieter_heap_tree_init(node, NULL, old_order - 1); */ + previous_tree = tree_to_pop->largest_order; + vieter_heap_node_free(tree_to_pop); -/* uint8_t i = 2; */ -/* while (node->next_largest_order != NULL) { */ -/* node = node->next_largest_order; */ -/* previous_tree = vieter_heap_tree_init(node, previous_tree, old_order - - * i); */ + tree = previous_tree->ptr.next_largest_order; + previous_tree->ptr.next_tree = NULL; -/* i++; */ -/* } */ + vieter_heap_node *next_tree; -/* return vieter_heap_tree_merge(tree_out, previous_tree); */ -/* } */ + while (tree != NULL) { + next_tree = tree->ptr.next_largest_order; + tree->ptr.next_tree = previous_tree; + + previous_tree = tree; + tree = next_tree; + } + + // original_root is zero if the heap only contained a single tree. + if (original_root != NULL) { + return vieter_heap_tree_merge(original_root, previous_tree); + } else { + return previous_tree; + } +} diff --git a/test/heap/test_heap.c b/test/heap/test_heap.c index f795ebe..74736a3 100644 --- a/test/heap/test_heap.c +++ b/test/heap/test_heap.c @@ -51,35 +51,35 @@ void test_insert() { vieter_heap_free(heap); } -/* void test_pop() { */ -/* vieter_heap *heap = vieter_heap_init(); */ -/* TEST_SIZE(heap, 0); */ +void test_pop() { + vieter_heap *heap = vieter_heap_init(); + TEST_SIZE(heap, 0); -/* void *data; */ + void *data; -/* for (uint64_t i = 50; i > 0; i--) { */ -/* vieter_heap_insert(heap, i, (void *)i); */ -/* TEST_SIZE(heap, (uint64_t)51 - i); */ + for (uint64_t i = 50; i > 0; i--) { + vieter_heap_insert(heap, i, (void *)i); + TEST_SIZE(heap, (uint64_t)51 - i); -/* TEST_CHECK(vieter_heap_peek(&data, heap) == vieter_heap_ok); */ -/* TEST_CHECK(data == (void*)i); */ -/* } */ + TEST_CHECK(vieter_heap_peek(&data, heap) == vieter_heap_ok); + TEST_CHECK(data == (void*)i); + } -/* data = NULL; */ + 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); */ -/* } */ + 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); */ -/* } */ + vieter_heap_free(heap); +} TEST_LIST = { {"init", test_init}, {"merge same order", test_merge_same_order}, {"insert", test_insert}, - /* {"pop", test_pop}, */ + {"pop", test_pop}, {NULL, NULL} }; From 63100c5b99aeecb488854a05382229689e81dd3e Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Tue, 24 Jan 2023 21:19:08 +0100 Subject: [PATCH 2/2] test(heap): add random test that exposes some faults --- src/heap/vieter_heap_tree.h | 27 +++++++++++++++++---- test/heap/test_heap.c | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/heap/vieter_heap_tree.h b/src/heap/vieter_heap_tree.h index b7597f6..c3bc55d 100644 --- a/src/heap/vieter_heap_tree.h +++ b/src/heap/vieter_heap_tree.h @@ -9,28 +9,45 @@ typedef struct vieter_heap_node { void *data; struct vieter_heap_node *largest_order; union { - struct vieter_heap_node *next_tree; - struct vieter_heap_node *next_largest_order; + // Roots point to next tree in the heap, other nodes point to their first + // neighbour. + struct vieter_heap_node *next_tree; + struct vieter_heap_node *next_largest_order; } ptr; uint8_t order; } vieter_heap_node; +/* + * Allocate an initialize a heap node object. + */ vieter_heap_node *vieter_heap_node_init(); +/* + * Deallocate a node object. + */ void vieter_heap_node_free(vieter_heap_node *node); -/* 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. + * Deallocate a node's entire structure. */ void vieter_heap_tree_free(vieter_heap_node *root); +/* + * Given the roots of the smallest trees in two heaps, merge them into a single + * large heap. + */ vieter_heap_node *vieter_heap_tree_merge(vieter_heap_node *root_a, vieter_heap_node *root_b); +/* + * Given the roots of two trees of the same order, merge them into a heap of one + * order larger. + */ vieter_heap_node *vieter_heap_tree_merge_same_order(vieter_heap_node *root_a, vieter_heap_node *root_b); +/* + * Remove the smallest element from the given heap. + */ vieter_heap_node *vieter_heap_tree_pop(void **out, vieter_heap_node *root); #endif diff --git a/test/heap/test_heap.c b/test/heap/test_heap.c index 74736a3..e136d87 100644 --- a/test/heap/test_heap.c +++ b/test/heap/test_heap.c @@ -1,6 +1,7 @@ #include "acutest.h" #include "vieter_heap.h" #include "vieter_heap_tree.h" +#include #define TEST_SIZE(heap, size) \ TEST_CHECK(vieter_heap_size(heap) == size); \ @@ -76,10 +77,57 @@ void test_pop() { vieter_heap_free(heap); } +int uint64_t_compare(const void *a, const void *b) { + if ((*(uint64_t *)a) < (*(uint64_t *)b)) { + return -1; + } else if ((*(uint64_t *)a) < (*(uint64_t *)b)) { + return 1; + } else { + return 0; + } +} + +void test_pop_random() { + srand(0); + + vieter_heap *heap = vieter_heap_init(); + + uint64_t *numbers = malloc(500 * sizeof(uint64_t)); + uint64_t num; + + for (uint64_t i = 0; i < 500; i++) { + num = rand(); + vieter_heap_insert(heap, num, (void *)num); + TEST_SIZE(heap, i + 1); + + numbers[i] = num; + } + + + qsort(numbers, 500, sizeof(uint64_t), uint64_t_compare); + + void *data = NULL; + + for (uint64_t i = 0; i < 500; i++) { + TEST_CHECK(vieter_heap_peek(&data, heap) == vieter_heap_ok); + TEST_CHECK(data == (void *)numbers[i]); + + data = NULL; + + TEST_CHECK(vieter_heap_pop(&data, heap) == vieter_heap_ok); + TEST_CHECK(data == (void *)numbers[i]); + TEST_SIZE(heap, (uint64_t)500 - i - 1); + } + + vieter_heap_free(heap); + free(numbers); +} + TEST_LIST = { {"init", test_init}, {"merge same order", test_merge_same_order}, {"insert", test_insert}, {"pop", test_pop}, + {"pop random", test_pop_random}, {NULL, NULL} };