libvieter/src/heap/vieter_heap_tree.c

196 lines
4.9 KiB
C

#include "vieter_heap_tree.h"
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_node *root) {
if (root->order == 0) {
goto end;
}
uint64_t size = 1;
vieter_heap_node **stack =
malloc(((uint64_t)1 << root->order) * sizeof(vieter_heap_node *));
stack[0] = root->largest_order;
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->ptr.next_largest_order != NULL) {
stack[size] = node->ptr.next_largest_order;
size++;
}
vieter_heap_node_free(node);
}
free(stack);
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;
if (root_a->key <= root_b->key) {
new_root = root_a;
root_b->ptr.next_largest_order = root_a->largest_order;
root_a->largest_order = root_b;
} else {
new_root = root_b;
root_a->ptr.next_largest_order = root_b->largest_order;
root_b->largest_order = root_a;
}
new_root->order++;
return new_root;
}
vieter_heap_node *vieter_heap_tree_merge(vieter_heap_node *root_a,
vieter_heap_node *root_b) {
vieter_heap_node *root, *target, *out;
if (root_a->order <= root_b->order) {
target = root_a;
root = root_b;
} else {
target = root_b;
root = root_a;
}
vieter_heap_node *next_tree, *next_target;
vieter_heap_node *previous_target = NULL;
while (target != NULL && root != NULL) {
if (target->order == root->order) {
next_tree = root->ptr.next_tree;
next_target = target->ptr.next_tree;
target = vieter_heap_tree_merge_same_order(target, root);
target->ptr.next_tree = next_target;
// 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
// trees until we no longer have a duplicate depth.
while (target->ptr.next_tree != NULL &&
target->ptr.next_tree->order == target->order) {
next_target = target->ptr.next_tree->ptr.next_tree;
target =
vieter_heap_tree_merge_same_order(target, target->ptr.next_tree);
target->ptr.next_tree = next_target;
}
if (previous_target != NULL) {
previous_target->ptr.next_tree = target;
} else {
out = target;
}
root = next_tree;
} else if (target->order > root->order) {
next_tree = root->ptr.next_tree;
if (previous_target == NULL) {
previous_target = root;
out = root;
} else {
previous_target->ptr.next_tree = root;
}
root->ptr.next_tree = target;
root = next_tree;
} else {
if (previous_target == NULL) {
out = target;
}
previous_target = target;
target = target->ptr.next_tree;
}
}
// Append final part of tree to target
if (target == NULL) {
previous_target->ptr.next_tree = root;
}
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; */
/* uint64_t smallest_key = tree->root->key; */
/* while (tree->next != NULL) { */
/* previous_tree = tree; */
/* tree = tree->next; */
/* if (tree->root->key < smallest_key) { */
/* smallest_key = tree->root->key; */
/* *out = tree->root->data; */
/* tree_before_smallest = previous_tree; */
/* } */
/* } */
/* if (tree_before_smallest != NULL) { */
/* previous_tree->next = tree->next; */
/* } else { */
/* tree_out = tree_out->next; */
/* } */
/* if (tree->order == 0) { */
/* vieter_heap_tree_free(tree); */
/* return NULL; */
/* } */
/* uint8_t old_order = tree->order; */
/* vieter_heap_node *node = tree->root->largest_order; */
/* free(tree->root); */
/* previous_tree = vieter_heap_tree_init(node, NULL, old_order - 1); */
/* 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); */
/* i++; */
/* } */
/* return vieter_heap_tree_merge(tree_out, previous_tree); */
/* } */