Paul Brinkmeier afe0276961
All checks were successful
continuous-integration/drone/push Build is passing
Move tests.h to header
2022-10-25 17:18:17 +02:00

226 lines
5.1 KiB
C

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "tests.h"
struct PHeapNode {
int key;
struct PHeapNode *parent;
struct PHeapNode *left;
struct PHeapNode *right;
struct PHeapNode *children;
};
void phn_init(struct PHeapNode *phn, int key) {
phn->key = key;
phn->parent = NULL;
phn->left = NULL;
phn->right = NULL;
phn->children = NULL;
}
static void phn_list_insert(struct PHeapNode **phn, struct PHeapNode *h) {
if (*phn == NULL) {
// list empty ==> h is only element now
h->left = h;
h->right = h;
*phn = h;
} else {
// list not empty ==> insert at the end
(*phn)->left->right = h;
h->left = (*phn)->left;
h->right = *phn;
(*phn)->left = h;
}
}
static void phn_list_remove(struct PHeapNode **phn, struct PHeapNode *h) {
assert(*phn != NULL);
if (h->left == h) {
assert(h->right == h);
// empty list
*phn = NULL;
} else {
// rearrange pointers
struct PHeapNode *tmp = h->left;
h->left->right = h->right;
h->right->left = tmp;
if (*phn == h) {
*phn = h->left;
}
}
h->parent = NULL;
h->left = NULL;
h->right = NULL;
}
// returns a or b
struct PHeapNode *phn_union(struct PHeapNode *a, struct PHeapNode *b) {
struct PHeapNode *min = a->key < b->key ? a : b;
struct PHeapNode *max = a->key < b->key ? b : a;
phn_list_insert(&min->children, max);
return min;
}
struct PHeap {
struct PHeapNode *roots;
struct PHeapNode *min;
};
void ph_init(struct PHeap *ph) {
ph->roots = NULL;
ph->min = NULL;
}
void ph_print(struct PHeap *ph) {
printf("roots: ");
if (ph->roots != NULL) {
struct PHeapNode *first = ph->roots;
struct PHeapNode *curr = first;
do {
printf("--{%d}", curr->key);
if (ph->min == curr) {
printf("'");
}
curr = curr->right;
} while (curr != first);
}
printf("--\n");
}
void ph_newtree(struct PHeap *ph, struct PHeapNode *h) {
assert(h->parent == NULL);
phn_list_insert(&ph->roots, h);
if (ph->min == NULL || h->key < ph->min->key) {
ph->min = h;
}
}
void ph_insert_malloc(struct PHeap *ph, int key) {
struct PHeapNode *h = malloc(sizeof(struct PHeapNode));
phn_init(h, key);
ph_newtree(ph, h);
}
struct PHeapNode *ph_deletemin(struct PHeap *ph) {
if (ph->min == NULL) {
return NULL;
}
struct PHeapNode *m = ph->min;
// forest := forest \ {m}
phn_list_remove(&ph->roots, m);
ph->min = NULL;
// foreach child h of m do newTree(h)
while (m->children != NULL) {
struct PHeapNode *curr = m->children;
phn_list_remove(&m->children, m->children);
ph_newtree(ph, curr);
}
// perform pair-wise union operations on the roots in forest
// update minPtr
if (ph->roots != NULL) {
struct PHeapNode *new_roots = NULL;
while (ph->roots != NULL && ph->roots->right != ph->roots) {
// while two elements are available:
struct PHeapNode *a = ph->roots;
struct PHeapNode *b = ph->roots->right;
phn_list_remove(&ph->roots, a);
phn_list_remove(&ph->roots, b);
a = phn_union(a, b);
phn_list_insert(&new_roots, a);
if (ph->min == NULL || a->key < ph->min->key) {
ph->min = a;
}
}
if (ph->roots != NULL) {
// another element remains
struct PHeapNode *last = ph->roots;
phn_list_remove(&ph->roots, last);
phn_list_insert(&new_roots, last);
if (ph->min == NULL || last->key < ph->min->key) {
ph->min = last;
}
}
assert(ph->roots == NULL);
ph->roots = new_roots;
}
return m;
}
void ph_deinit_free(struct PHeap *ph) {
while (ph->min != NULL) {
struct PHeapNode *h = ph_deletemin(ph);
free(h);
}
}
int cmp_int(const void *a, const void *b) {
return *((int *) a) - *((int *) b);
}
int main() {
TEST("consecutive deleteMin calls yield increasing results", {
srand(2309);
struct PHeap ph;
ph_init(&ph);
for (int i = 0; i < 1000; i++) {
ph_insert_malloc(&ph, rand());
}
int max = INT_MIN;
while (ph.min != NULL) {
struct PHeapNode *h = ph_deletemin(&ph);
ASSERT(h->key >= max);
max = h->key;
free(h);
}
ph_deinit_free(&ph);
})
TEST("deleteMin yields the same order as qsort", {
srand(2309);
struct PHeap ph;
ph_init(&ph);
int n = 1000;
int xs[n];
for (int i = 0; i < n; i++) {
xs[i] = rand();
ph_insert_malloc(&ph, xs[i]);
}
qsort(xs, n, sizeof(int), cmp_int);
for (int i = 0; i < n; i++) {
struct PHeapNode *h = ph_deletemin(&ph);
ASSERT(h->key == xs[i]);
free(h);
}
ASSERT(ph.min == NULL);
ph_deinit_free(&ph);
})
DONE
}