refactor(heap): combine tree and node into single struct

min-heap
Jef Roosens 2023-01-24 17:22:11 +01:00
parent 09c488aa0f
commit 95d8c9972b
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
4 changed files with 171 additions and 179 deletions

View File

@ -4,30 +4,30 @@
#include <stdlib.h> #include <stdlib.h>
struct vieter_heap { struct vieter_heap {
vieter_heap_tree *tree; vieter_heap_node *tree;
}; };
vieter_heap *vieter_heap_init() { return calloc(1, sizeof(vieter_heap)); } vieter_heap *vieter_heap_init() { return calloc(1, sizeof(vieter_heap)); }
uint64_t vieter_heap_size(vieter_heap *heap) { uint64_t vieter_heap_size(vieter_heap *heap) {
uint64_t size = 0; uint64_t size = 0;
vieter_heap_tree *tree = heap->tree; vieter_heap_node *tree = heap->tree;
while (tree != NULL) { while (tree != NULL) {
size |= (uint64_t)1 << tree->order; size |= (uint64_t)1 << tree->order;
tree = tree->next; tree = tree->ptr.next_tree;
} }
return size; return size;
} }
void vieter_heap_free(vieter_heap *heap) { void vieter_heap_free(vieter_heap *heap) {
vieter_heap_tree *tree = heap->tree; vieter_heap_node *tree = heap->tree;
vieter_heap_tree *next; vieter_heap_node *next;
while (tree != NULL) { while (tree != NULL) {
next = tree->next; next = tree->ptr.next_tree;
vieter_heap_tree_free(tree); vieter_heap_tree_free(tree);
tree = next; tree = next;
} }
@ -37,10 +37,10 @@ void vieter_heap_free(vieter_heap *heap) {
vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key, vieter_heap_error vieter_heap_insert(vieter_heap *heap, uint64_t key,
void *data) { void *data) {
vieter_heap_node *new_node = vieter_heap_node_init(); vieter_heap_node *new_tree = vieter_heap_node_init();
new_node->key = key; new_tree->key = key;
new_node->data = data; new_tree->data = data;
vieter_heap_tree *new_tree = vieter_heap_tree_init(new_node, NULL, 0); new_tree->order = 0;
if (heap->tree == NULL) { if (heap->tree == NULL) {
heap->tree = new_tree; heap->tree = new_tree;
@ -51,39 +51,39 @@ 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) { */
*out = heap->tree->root->data; /* *out = heap->tree->root->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); /* 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) {
return vieter_heap_empty; return vieter_heap_empty;
} }
vieter_heap_tree *tree = heap->tree; vieter_heap_node *tree = heap->tree;
uint64_t smallest_key = tree->root->key; uint64_t smallest_key = tree->key;
*out = tree->root->data; *out = tree->data;
while (tree->next != NULL) { while (tree->ptr.next_tree != NULL) {
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; *out = tree->data;
} }
} }

View File

@ -6,11 +6,15 @@ vieter_heap_node *vieter_heap_node_init() {
void vieter_heap_node_free(vieter_heap_node *node) { free(node); } void vieter_heap_node_free(vieter_heap_node *node) { free(node); }
void vieter_heap_tree_free(vieter_heap_tree *tree) { void vieter_heap_tree_free(vieter_heap_node *root) {
if (root->order == 0) {
goto end;
}
uint64_t size = 1; uint64_t size = 1;
vieter_heap_node **stack = vieter_heap_node **stack =
malloc(((uint64_t)1 << tree->order) * sizeof(vieter_heap_node *)); malloc(((uint64_t)1 << root->order) * sizeof(vieter_heap_node *));
stack[0] = tree->root; stack[0] = root->largest_order;
vieter_heap_node *node; vieter_heap_node *node;
@ -23,8 +27,8 @@ void vieter_heap_tree_free(vieter_heap_tree *tree) {
size++; size++;
} }
if (node->next_largest_order != NULL) { if (node->ptr.next_largest_order != NULL) {
stack[size] = node->next_largest_order; stack[size] = node->ptr.next_largest_order;
size++; size++;
} }
@ -32,170 +36,160 @@ void vieter_heap_tree_free(vieter_heap_tree *tree) {
} }
free(stack); free(stack);
free(tree);
end:
vieter_heap_node_free(root);
} }
vieter_heap_tree *vieter_heap_tree_init(vieter_heap_node *root, /* vieter_heap_tree *vieter_heap_tree_init(vieter_heap_node *root, */
vieter_heap_tree *next, uint8_t order) { /* vieter_heap_tree *next, uint8_t
vieter_heap_tree *tree = malloc(sizeof(vieter_heap_tree)); * order) { */
/* vieter_heap_tree *tree = malloc(sizeof(vieter_heap_tree)); */
tree->root = root; /* tree->root = root; */
tree->next = next; /* tree->next = next; */
tree->order = order; /* tree->order = order; */
return tree; /* return tree; */
} /* } */
void vieter_heap_tree_swap(vieter_heap_tree *t1, vieter_heap_tree *t2) { vieter_heap_node *vieter_heap_tree_merge_same_order(vieter_heap_node *root_a,
vieter_heap_tree temp = { vieter_heap_node *root_b) {
.order = t1->order, .root = t1->root, .next = t1->next}; vieter_heap_node *new_root;
t1->order = t2->order; if (root_a->key <= root_b->key) {
t1->root = t2->root; new_root = root_a;
t1->next = t2->next; root_b->ptr.next_largest_order = root_a->largest_order;
root_a->largest_order = root_b;
t2->order = temp.order;
t2->root = temp.root;
t2->next = temp.next;
}
vieter_heap_tree *vieter_heap_tree_merge_same_order(vieter_heap_tree *tree_a,
vieter_heap_tree *tree_b) {
vieter_heap_tree *new_tree;
if (tree_a->root->key <= tree_b->root->key) {
new_tree = tree_a;
tree_a->root->next_largest_order = tree_a->root->largest_order;
tree_a->root->largest_order = tree_b->root;
free(tree_b);
} else { } else {
new_tree = tree_b; new_root = root_b;
tree_b->root->next_largest_order = tree_b->root->largest_order; root_a->ptr.next_largest_order = root_b->largest_order;
tree_b->root->largest_order = tree_a->root; root_b->largest_order = root_a;
free(tree_a);
} }
new_tree->order++; new_root->order++;
return new_tree; return new_root;
} }
vieter_heap_tree *vieter_heap_tree_merge(vieter_heap_tree *tree_a, vieter_heap_node *vieter_heap_tree_merge(vieter_heap_node *root_a,
vieter_heap_tree *tree_b) { vieter_heap_node *root_b) {
vieter_heap_tree *tree, *target, *out; vieter_heap_node *root, *target, *out;
if (tree_a->order <= tree_b->order) { if (root_a->order <= root_b->order) {
target = tree_a; target = root_a;
tree = tree_b; root = root_b;
} else { } else {
target = tree_b; target = root_b;
tree = tree_a; root = root_a;
} }
vieter_heap_tree *next_tree, *next_target; vieter_heap_node *next_tree, *next_target;
vieter_heap_tree *previous_target = NULL; vieter_heap_node *previous_target = NULL;
while (target != NULL && tree != NULL) { while (target != NULL && root != NULL) {
if (target->order == tree->order) { if (target->order == root->order) {
next_tree = tree->next; next_tree = root->ptr.next_tree;
next_target = target->next; next_target = target->ptr.next_tree;
target = vieter_heap_tree_merge_same_order(target, tree); target = vieter_heap_tree_merge_same_order(target, root);
target->next = next_target; target->ptr.next_tree = next_target;
// If this merge produces a binomial tree whose size is already in // If this merge produces a binomial tree whose size is already in
// target, it will be the next target. Therefore, we can merge target's // target, it will be the next target. Therefore, we can merge target's
// trees until we no longer have a duplicate depth. // trees until we no longer have a duplicate depth.
while (target->next != NULL && target->next->order == target->order) { while (target->ptr.next_tree != NULL &&
next_target = target->next->next; target->ptr.next_tree->order == target->order) {
target = vieter_heap_tree_merge_same_order(target, target->next); next_target = target->ptr.next_tree->ptr.next_tree;
target->next = next_target; target =
vieter_heap_tree_merge_same_order(target, target->ptr.next_tree);
target->ptr.next_tree = next_target;
} }
if (previous_target != NULL) { if (previous_target != NULL) {
previous_target->next = target; previous_target->ptr.next_tree = target;
} else { } else {
out = target; out = target;
} }
tree = next_tree; root = next_tree;
} else if (target->order > tree->order) { } else if (target->order > root->order) {
next_tree = tree->next; next_tree = root->ptr.next_tree;
if (previous_target == NULL) { if (previous_target == NULL) {
previous_target = tree; previous_target = root;
out = tree; out = root;
} else { } else {
previous_target->next = tree; previous_target->ptr.next_tree = root;
} }
tree->next = target; root->ptr.next_tree = target;
tree = next_tree; root = next_tree;
} else { } else {
if (previous_target == NULL) { if (previous_target == NULL) {
out = target; out = target;
} }
previous_target = target; previous_target = target;
target = target->next; target = target->ptr.next_tree;
} }
} }
// Append final part of tree to target // Append final part of tree to target
if (target == NULL) { if (target == NULL) {
previous_target->next = tree; previous_target->ptr.next_tree = root;
} }
return out; return out;
} }
vieter_heap_tree *vieter_heap_tree_pop(void **out, vieter_heap_tree *tree) { /* 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_before_smallest = NULL; */
vieter_heap_tree *tree_out = tree; /* vieter_heap_tree *previous_tree = NULL; */
/* vieter_heap_tree *tree_out = tree; */
uint64_t smallest_key = tree->root->key; /* uint64_t smallest_key = tree->root->key; */
while (tree->next != NULL) { /* while (tree->next != NULL) { */
previous_tree = tree; /* previous_tree = tree; */
tree = tree->next; /* tree = tree->next; */
if (tree->root->key < smallest_key) { /* if (tree->root->key < smallest_key) { */
smallest_key = tree->root->key; /* smallest_key = tree->root->key; */
*out = tree->root->data; /* *out = tree->root->data; */
tree_before_smallest = previous_tree; /* tree_before_smallest = previous_tree; */
} /* } */
} /* } */
if (tree_before_smallest != NULL) { /* if (tree_before_smallest != NULL) { */
previous_tree->next = tree->next; /* previous_tree->next = tree->next; */
} else { /* } else { */
tree_out = tree_out->next; /* tree_out = tree_out->next; */
} /* } */
if (tree->order == 0) { /* if (tree->order == 0) { */
vieter_heap_tree_free(tree); /* vieter_heap_tree_free(tree); */
return NULL; /* return NULL; */
} /* } */
uint8_t old_order = tree->order; /* uint8_t old_order = tree->order; */
vieter_heap_node *node = tree->root->largest_order; /* vieter_heap_node *node = tree->root->largest_order; */
free(tree->root); /* free(tree->root); */
previous_tree = vieter_heap_tree_init(node, NULL, old_order - 1); /* previous_tree = vieter_heap_tree_init(node, NULL, old_order - 1); */
uint8_t i = 2; /* uint8_t i = 2; */
while (node->next_largest_order != NULL) { /* while (node->next_largest_order != NULL) { */
node = node->next_largest_order; /* node = node->next_largest_order; */
previous_tree = vieter_heap_tree_init(node, previous_tree, old_order - i); /* previous_tree = vieter_heap_tree_init(node, previous_tree, old_order -
* i); */
i++; /* i++; */
} /* } */
return vieter_heap_tree_merge(tree_out, previous_tree); /* return vieter_heap_tree_merge(tree_out, previous_tree); */
} /* } */

View File

@ -8,31 +8,29 @@ typedef struct vieter_heap_node {
uint64_t key; uint64_t key;
void *data; void *data;
struct vieter_heap_node *largest_order; struct vieter_heap_node *largest_order;
struct vieter_heap_node *next_largest_order; union {
struct vieter_heap_node *next_tree;
struct vieter_heap_node *next_largest_order;
} ptr;
uint8_t order;
} vieter_heap_node; } vieter_heap_node;
vieter_heap_node *vieter_heap_node_init(); vieter_heap_node *vieter_heap_node_init();
void vieter_heap_node_free(vieter_heap_node *node); void vieter_heap_node_free(vieter_heap_node *node);
typedef struct vieter_heap_tree { /* vieter_heap_tree *vieter_heap_tree_init(vieter_heap_node *root, vieter_heap_tree *next, uint8_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, uint8_t order);
/* /*
* Deallocate a tree object, along with its underlying tree structure. * Deallocate a tree object, along with its underlying tree structure.
*/ */
void vieter_heap_tree_free(vieter_heap_tree *tree); void vieter_heap_tree_free(vieter_heap_node *root);
vieter_heap_tree *vieter_heap_tree_merge(vieter_heap_tree *tree_a, vieter_heap_tree *tree_b); vieter_heap_node *vieter_heap_tree_merge(vieter_heap_node *root_a, vieter_heap_node *root_b);
vieter_heap_tree *vieter_heap_tree_merge_same_order(vieter_heap_tree *tree_a, vieter_heap_node *vieter_heap_tree_merge_same_order(vieter_heap_node *root_a,
vieter_heap_tree *tree_b); vieter_heap_node *root_b);
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 *root);
#endif #endif

View File

@ -16,18 +16,18 @@ void test_init() {
void test_merge_same_order() { void test_merge_same_order() {
vieter_heap_node *root_a = vieter_heap_node_init(); vieter_heap_node *root_a = vieter_heap_node_init();
root_a->key = 1; root_a->key = 1;
vieter_heap_tree *tree_a = vieter_heap_tree_init(root_a, NULL, 1); root_a->order = 0;
vieter_heap_node *root_b = vieter_heap_node_init(); vieter_heap_node *root_b = vieter_heap_node_init();
root_b->key = 2; root_b->key = 2;
vieter_heap_tree *tree_b = vieter_heap_tree_init(root_b, NULL, 1); root_b->order = 0;
vieter_heap_tree *merged = vieter_heap_tree_merge_same_order(tree_a, tree_b); vieter_heap_node *merged = vieter_heap_tree_merge_same_order(root_a, root_b);
TEST_CHECK(merged == tree_a); TEST_CHECK(merged == root_a);
TEST_CHECK(merged->root->key == 1); TEST_CHECK(merged->key == 1);
TEST_CHECK(merged->root->largest_order == root_b); TEST_CHECK(merged->largest_order == root_b);
TEST_CHECK(merged->root->next_largest_order == NULL); TEST_CHECK(merged->ptr.next_largest_order == NULL);
vieter_heap_tree_free(merged); vieter_heap_tree_free(merged);
} }
@ -51,35 +51,35 @@ 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); */
} /* } */
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}, */
{NULL, NULL} {NULL, NULL}
}; };