#include #include #include #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 }