Compare commits

...

2 Commits

Author SHA1 Message Date
Jef Roosens 63100c5b99
test(heap): add random test that exposes some faults
ci/woodpecker/pr/lint Pipeline was successful Details
ci/woodpecker/pr/test Pipeline failed Details
ci/woodpecker/pr/test-mem unknown status Details
2023-01-24 21:19:08 +01:00
Jef Roosens 6845e67cb6
feat(heap): possibly working pop 2023-01-24 21:02:29 +01:00
4 changed files with 148 additions and 86 deletions

View File

@ -51,23 +51,23 @@ vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key,
return vieter_heap_ok; return vieter_heap_ok;
} }
/* vieter_heap_error vieter_heap_pop(void **out, vieter_heap *heap) { */ vieter_heap_error vieter_heap_pop(void **out, vieter_heap *heap) {
/* if (heap->tree == NULL) { */ if (heap->tree == NULL) {
/* return vieter_heap_empty; */ return vieter_heap_empty;
/* } */ }
/* if (heap->tree->order == 0) { */ if (heap->tree->order == 0 && heap->tree->ptr.next_tree == NULL) {
/* *out = heap->tree->root->data; */ *out = heap->tree->data;
/* vieter_heap_tree_free(heap->tree); */ vieter_heap_tree_free(heap->tree);
/* heap->tree = NULL; */ 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) { vieter_heap_error vieter_heap_peek(void **out, vieter_heap *heap) {
if (heap->tree == NULL) { if (heap->tree == NULL) {

View File

@ -41,18 +41,6 @@ end:
vieter_heap_node_free(root); 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 *vieter_heap_tree_merge_same_order(vieter_heap_node *root_a,
vieter_heap_node *root_b) { vieter_heap_node *root_b) {
vieter_heap_node *new_root; vieter_heap_node *new_root;
@ -144,52 +132,61 @@ vieter_heap_node *vieter_heap_tree_merge(vieter_heap_node *root_a,
return out; return out;
} }
/* vieter_heap_tree *vieter_heap_tree_pop(void **out, vieter_heap_tree *tree) { vieter_heap_node *vieter_heap_tree_pop(void **out, vieter_heap_node *tree) {
*/ vieter_heap_node *tree_before_smallest = NULL;
/* vieter_heap_tree *tree_before_smallest = NULL; */ vieter_heap_node *previous_tree = NULL;
/* vieter_heap_tree *previous_tree = NULL; */ vieter_heap_node *original_root = tree;
/* vieter_heap_tree *tree_out = tree; */
/* uint64_t smallest_key = tree->root->key; */ uint64_t smallest_key = tree->key;
/* while (tree->next != NULL) { */ while (tree->ptr.next_tree != NULL) {
/* previous_tree = tree; */ previous_tree = tree;
/* tree = tree->next; */ tree = tree->ptr.next_tree;
/* if (tree->root->key < smallest_key) { */ if (tree->key < smallest_key) {
/* smallest_key = tree->root->key; */ smallest_key = tree->key;
/* *out = tree->root->data; */ tree_before_smallest = previous_tree;
/* tree_before_smallest = previous_tree; */ }
/* } */ }
/* } */
/* if (tree_before_smallest != NULL) { */ vieter_heap_node *tree_to_pop;
/* previous_tree->next = tree->next; */
/* } else { */
/* tree_out = tree_out->next; */
/* } */
/* if (tree->order == 0) { */ if (tree_before_smallest != NULL) {
/* vieter_heap_tree_free(tree); */ 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; */ return original_root;
/* free(tree->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; */ tree = previous_tree->ptr.next_largest_order;
/* while (node->next_largest_order != NULL) { */ previous_tree->ptr.next_tree = NULL;
/* node = node->next_largest_order; */
/* previous_tree = vieter_heap_tree_init(node, previous_tree, old_order -
* i); */
/* 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;
}
}

View File

@ -9,28 +9,45 @@ typedef struct vieter_heap_node {
void *data; void *data;
struct vieter_heap_node *largest_order; struct vieter_heap_node *largest_order;
union { union {
// 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_tree;
struct vieter_heap_node *next_largest_order; struct vieter_heap_node *next_largest_order;
} ptr; } ptr;
uint8_t order; uint8_t order;
} vieter_heap_node; } vieter_heap_node;
/*
* Allocate an initialize a heap node object.
*/
vieter_heap_node *vieter_heap_node_init(); vieter_heap_node *vieter_heap_node_init();
/*
* Deallocate a node object.
*/
void vieter_heap_node_free(vieter_heap_node *node); 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); 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); 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 *vieter_heap_tree_merge_same_order(vieter_heap_node *root_a,
vieter_heap_node *root_b); 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); vieter_heap_node *vieter_heap_tree_pop(void **out, vieter_heap_node *root);
#endif #endif

View File

@ -1,6 +1,7 @@
#include "acutest.h" #include "acutest.h"
#include "vieter_heap.h" #include "vieter_heap.h"
#include "vieter_heap_tree.h" #include "vieter_heap_tree.h"
#include <stdlib.h>
#define TEST_SIZE(heap, size) \ #define TEST_SIZE(heap, size) \
TEST_CHECK(vieter_heap_size(heap) == size); \ TEST_CHECK(vieter_heap_size(heap) == size); \
@ -51,35 +52,82 @@ void test_insert() {
vieter_heap_free(heap); vieter_heap_free(heap);
} }
/* void test_pop() { */ void test_pop() {
/* vieter_heap *heap = vieter_heap_init(); */ vieter_heap *heap = vieter_heap_init();
/* TEST_SIZE(heap, 0); */ TEST_SIZE(heap, 0);
/* void *data; */ 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); */ vieter_heap_insert(heap, i, (void *)i);
/* TEST_SIZE(heap, (uint64_t)51 - i); */ TEST_SIZE(heap, (uint64_t)51 - i);
/* TEST_CHECK(vieter_heap_peek(&data, heap) == vieter_heap_ok); */ TEST_CHECK(vieter_heap_peek(&data, heap) == vieter_heap_ok);
/* TEST_CHECK(data == (void*)i); */ TEST_CHECK(data == (void*)i);
/* } */ }
/* data = NULL; */ data = NULL;
/* for (uint64_t i = 1; i <= 50; i++) { */ for (uint64_t i = 1; i <= 50; i++) {
/* TEST_CHECK(vieter_heap_pop(&data, heap) == vieter_heap_ok); */ TEST_CHECK(vieter_heap_pop(&data, heap) == vieter_heap_ok);
/* TEST_CHECK(data == (void*)i); */ TEST_CHECK(data == (void*)i);
/* TEST_SIZE(heap, (uint64_t)50 - i); */ TEST_SIZE(heap, (uint64_t)50 - i);
/* } */ }
/* vieter_heap_free(heap); */ 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 = { TEST_LIST = {
{"init", test_init}, {"init", test_init},
{"merge same order", test_merge_same_order}, {"merge same order", test_merge_same_order},
{"insert", test_insert}, {"insert", test_insert},
/* {"pop", test_pop}, */ {"pop", test_pop},
{"pop random", test_pop_random},
{NULL, NULL} {NULL, NULL}
}; };