refactor(heap): some better variable names; some more tests

pull/4/head
Jef Roosens 2023-01-25 22:12:22 +01:00
parent dc557f57ab
commit 3ec2e76af9
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
4 changed files with 83 additions and 54 deletions

View File

@ -1,12 +1,7 @@
#include "vieter_heap.h" #include "vieter_heap_internal.h"
#include "vieter_heap_tree.h"
#include <stdlib.h> #include <stdlib.h>
struct vieter_heap {
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) {

View File

@ -0,0 +1,6 @@
#include "vieter_heap.h"
#include "vieter_heap_tree.h"
struct vieter_heap {
vieter_heap_node *tree;
};

View File

@ -43,90 +43,91 @@ end:
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 *root, *child;
if (root_a->key <= root_b->key) { if (root_a->key <= root_b->key) {
new_root = root_a; root = root_a;
root_b->ptr.next_largest_order = root_a->largest_order; child = root_b;
root_a->largest_order = root_b;
} else { } else {
new_root = root_b; root = root_b;
root_a->ptr.next_largest_order = root_b->largest_order; child = root_a;
root_b->largest_order = root_a;
} }
new_root->order++; child->ptr.next_largest_order = root->largest_order;
root->largest_order = child;
return new_root; root->order++;
return root;
} }
vieter_heap_node *vieter_heap_tree_merge(vieter_heap_node *root_a, vieter_heap_node *vieter_heap_tree_merge(vieter_heap_node *root_a,
vieter_heap_node *root_b) { vieter_heap_node *root_b) {
vieter_heap_node *root, *target, *out; vieter_heap_node *other_tree, *target_tree, *out;
if (root_a->order <= root_b->order) { if (root_a->order <= root_b->order) {
target = root_a; target_tree = root_a;
root = root_b; other_tree = root_b;
} else { } else {
target = root_b; target_tree = root_b;
root = root_a; other_tree = root_a;
} }
vieter_heap_node *next_tree, *next_target; vieter_heap_node *next_other_tree, *next_target_tree;
vieter_heap_node *previous_target = NULL; vieter_heap_node *previous_target_tree = NULL;
while (target != NULL && root != NULL) { while (target_tree != NULL && other_tree != NULL) {
if (target->order == root->order) { if (target_tree->order == other_tree->order) {
next_tree = root->ptr.next_tree; next_other_tree = other_tree->ptr.next_tree;
next_target = target->ptr.next_tree; next_target_tree = target_tree->ptr.next_tree;
target = vieter_heap_tree_merge_same_order(target, root); target_tree = vieter_heap_tree_merge_same_order(target_tree, other_tree);
target->ptr.next_tree = next_target; target_tree->ptr.next_tree = next_target_tree;
// 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->ptr.next_tree != NULL && while (next_target_tree != NULL &&
target->ptr.next_tree->order == target->order) { next_target_tree->order == target_tree->order) {
next_target = target->ptr.next_tree->ptr.next_tree; next_target_tree = next_target_tree->ptr.next_tree;
target = target_tree = vieter_heap_tree_merge_same_order(
vieter_heap_tree_merge_same_order(target, target->ptr.next_tree); target_tree, target_tree->ptr.next_tree);
target->ptr.next_tree = next_target; target_tree->ptr.next_tree = next_target_tree;
} }
if (previous_target != NULL) { if (previous_target_tree != NULL) {
previous_target->ptr.next_tree = target; previous_target_tree->ptr.next_tree = target_tree;
} else { } else {
out = target; out = target_tree;
} }
root = next_tree; other_tree = next_other_tree;
} else if (target->order > root->order) { } else if (target_tree->order > other_tree->order) {
next_tree = root->ptr.next_tree; next_other_tree = other_tree->ptr.next_tree;
if (previous_target == NULL) { if (previous_target_tree == NULL) {
previous_target = root; previous_target_tree = other_tree;
out = root; out = other_tree;
} else { } else {
previous_target->ptr.next_tree = root; previous_target_tree->ptr.next_tree = other_tree;
} }
root->ptr.next_tree = target; other_tree->ptr.next_tree = target_tree;
root = next_tree; other_tree = next_other_tree;
} else { } else {
if (previous_target == NULL) { if (previous_target_tree == NULL) {
out = target; out = target_tree;
} }
previous_target = target; previous_target_tree = target_tree;
target = target->ptr.next_tree; target_tree = target_tree->ptr.next_tree;
} }
} }
// Append final part of tree to target // Append final part of tree to target
if (target == NULL) { if (target_tree == NULL) {
previous_target->ptr.next_tree = root; previous_target_tree->ptr.next_tree = other_tree;
} }
return out; return out;

View File

@ -1,6 +1,5 @@
#include "acutest.h" #include "acutest.h"
#include "vieter_heap.h" #include "vieter_heap_internal.h"
#include "vieter_heap_tree.h"
#include <stdlib.h> #include <stdlib.h>
#define TEST_SIZE(heap, size) \ #define TEST_SIZE(heap, size) \
@ -14,6 +13,29 @@ void test_init() {
vieter_heap_free(heap); vieter_heap_free(heap);
} }
void count_nodes(uint64_t *counter, vieter_heap_node *root) {
(*counter)++;
if (root->largest_order != NULL) {
count_nodes(counter, root->largest_order);
}
// This will also traverse the various trees
if (root->ptr.next_largest_order != NULL) {
count_nodes(counter, root->ptr.next_largest_order);
}
}
uint64_t count_nodes_heap(vieter_heap *heap) {
uint64_t counter = 0;
if (heap->tree != NULL) {
count_nodes(&counter, heap->tree);
}
return counter;
}
void test_insert() { void test_insert() {
vieter_heap *heap = vieter_heap_init(); vieter_heap *heap = vieter_heap_init();
TEST_SIZE(heap, 0); TEST_SIZE(heap, 0);
@ -23,6 +45,7 @@ void test_insert() {
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(count_nodes_heap(heap) == (uint64_t)51 - i);
data = 0; data = 0;
@ -47,6 +70,7 @@ void test_insert_random() {
for (uint64_t i = 0; i < 5000; i++) { for (uint64_t i = 0; i < 5000; i++) {
vieter_heap_insert(heap, num, (void *)num); vieter_heap_insert(heap, num, (void *)num);
TEST_SIZE(heap, i + 1); TEST_SIZE(heap, i + 1);
TEST_CHECK(count_nodes_heap(heap) == (uint64_t)i + 1);
if (num < smallest) { if (num < smallest) {
smallest = num; smallest = num;
@ -72,6 +96,7 @@ void test_pop() {
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(count_nodes_heap(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);
@ -112,6 +137,7 @@ void test_pop_random() {
num = rand(); num = rand();
vieter_heap_insert(heap, num, (void *)num); vieter_heap_insert(heap, num, (void *)num);
TEST_SIZE(heap, i + 1); TEST_SIZE(heap, i + 1);
TEST_CHECK(count_nodes_heap(heap) == i + 1);
numbers[i] = num; numbers[i] = num;
} }
@ -130,6 +156,7 @@ void test_pop_random() {
TEST_CHECK(vieter_heap_pop(&data, heap) == vieter_heap_ok); TEST_CHECK(vieter_heap_pop(&data, heap) == vieter_heap_ok);
TEST_CHECK_(data == (void *)numbers[i], "pop %lx == %lx", (uint64_t)data, numbers[i]); TEST_CHECK_(data == (void *)numbers[i], "pop %lx == %lx", (uint64_t)data, numbers[i]);
TEST_SIZE(heap, n - i - 1); TEST_SIZE(heap, n - i - 1);
TEST_CHECK(count_nodes_heap(heap) == n - i - 1);
} }
vieter_heap_free(heap); vieter_heap_free(heap);