#include #include #include struct RHeapNode { struct RHeapNode *left; struct RHeapNode *right; unsigned int key; }; // insert a node at the end of a list (left of the head) // Before: // ┌─┐ ┌────┐ ┌─┐ ┌─┐ // │l◄──►list◄──►r│ ◄─┤h├─► // └─┘ └────┘ └─┘ └─┘ // After: // ┌─┐ ┌─┐ ┌────┐ ┌─┐ // │l◄──►h◄──►list◄──►r│ // └─┘ └─┘ └────┘ └─┘ void rhn_insert(struct RHeapNode *list, struct RHeapNode *h) { assert(h->left == NULL); assert(h->right == NULL); list->left->right = h; h->left = list->left; h->right = list; list->left = h; } // remove a node from its list // Before: // ┌─┐ ┌─┐ ┌─┐ // │l◄──►h◄──►r│ // └─┘ └─┘ └─┘ // After: // ┌─┐ ┌─┐ ┌─┐ // │l◄──►r│ ◄─┤h├─► // └─┘ └─┘ └─┘ void rhn_remove(struct RHeapNode *h) { h->left->right = h->right; h->right->left = h->left; h->left = NULL; h->right = NULL; } struct RHeap { // last deleted element, initially 0 unsigned int min; size_t buckets_size; struct RHeapNode *buckets; }; static unsigned int log2(unsigned int x) { return 8 * sizeof(unsigned int) - __builtin_clz(x); } void rh_init(struct RHeap *rh, unsigned int c) { unsigned int k = 1 + log2(c); rh->min = 0; rh->buckets_size = 1 + k; // extra space for bucket -1 rh->buckets = malloc(rh->buckets_size * sizeof(struct RHeapNode)); for (size_t i = 0; i < rh->buckets_size; i++) { rh->buckets[i].left = &rh->buckets[i]; rh->buckets[i].right = &rh->buckets[i]; } } void rh_free(struct RHeap *rh) { free(rh->buckets); } static int msd(unsigned int x, unsigned int y) { return 8 * sizeof(unsigned int) - __builtin_clz(x ^ y) - 1; } static size_t min(size_t x, size_t y) { return x <= y ? x : y; } void rh_insert(struct RHeap *rh, struct RHeapNode *h) { size_t bucket = h->key == rh->min ? 0 : min(1 + msd(h->key, rh->min), rh->buckets_size - 1); rhn_insert(&rh->buckets[bucket], h); } struct RHeapNode *rh_insert_malloc(struct RHeap *rh, unsigned int key) { struct RHeapNode *h = malloc(sizeof(struct RHeapNode)); h->left = NULL; h->right = NULL; h->key = key; rh_insert(rh, h); return h; } void rh_print(struct RHeap *rh) { printf("d* = %u\n", rh->min); for (size_t i = 0; i < rh->buckets_size; i++) { printf("B[%3zd]:", (ssize_t) i - 1); struct RHeapNode *curr = rh->buckets[i].right; while (curr != &rh->buckets[i]) { printf(" %u", curr->key); curr = curr->right; } printf("\n"); } } struct RHeapNode *rh_deletemin(struct RHeap *rh) { // if bucket -1 is empty if (rh->buckets[0].right == &rh->buckets[0]) { assert(rh->buckets[0].left == &rh->buckets[0]); // find first non-empty bucket B[i] size_t i = 1; for (; rh->buckets[i].right == &rh->buckets[i]; i++) { assert(i < rh->buckets_size); } struct RHeapNode *bucket = &rh->buckets[i]; // find smallest element in B struct RHeapNode *minb = bucket->right; for (struct RHeapNode *curr = minb->right; curr != bucket; curr = curr->right) { if (curr->key < minb->key) { minb = curr; } } assert(minb != bucket); // update d* and move min(B[i]) to bucket -1 rh->min = minb->key; rhn_remove(minb); rhn_insert(&rh->buckets[0], minb); // move remaining elements of B[i] to bucket -1 while (bucket->right != bucket) { struct RHeapNode *tmp = bucket->right; rhn_remove(bucket->right); rh_insert(rh, tmp); } } assert(rh->buckets[0].right != &rh->buckets[0]); struct RHeapNode *minnode = rh->buckets[0].right; rhn_remove(minnode); return minnode; } static void insert_and_print(struct RHeap *rh, unsigned int key) { rh_insert_malloc(rh, key); printf("# After insert(%u):\n", key); rh_print(rh); } static void deletemin_and_print(struct RHeap *rh) { struct RHeapNode *h = rh_deletemin(rh); printf("# After deleteMin() == %u:\n", h->key); rh_print(rh); free(h); } int main() { struct RHeap rh; rh_init(&rh, 6); rh_insert_malloc(&rh, 5); struct RHeapNode *h = rh_deletemin(&rh); free(h); rh_print(&rh); insert_and_print(&rh, 6); insert_and_print(&rh, 10); insert_and_print(&rh, 7); deletemin_and_print(&rh); deletemin_and_print(&rh); insert_and_print(&rh, 12); deletemin_and_print(&rh); insert_and_print(&rh, 16); rh_free(&rh); }