All checks were successful
continuous-integration/drone/push Build is passing
226 lines
5.1 KiB
C
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
|
|
}
|