From 7775028b58c268dac700b3d49e096b31c1c9b3a4 Mon Sep 17 00:00:00 2001 From: Paul Brinkmeier Date: Wed, 14 Sep 2022 17:40:31 +0200 Subject: [PATCH] Add radix heap --- .drone.yml | 4 +- algo2/{ => pairingheap}/pairingheap.c | 0 algo2/radixheap/radixheap.c | 188 +++++++++++++++++++++++++- 3 files changed, 189 insertions(+), 3 deletions(-) rename algo2/{ => pairingheap}/pairingheap.c (100%) diff --git a/.drone.yml b/.drone.yml index 6fb8379..b42062a 100644 --- a/.drone.yml +++ b/.drone.yml @@ -13,10 +13,10 @@ steps: image: python:3.11-rc-alpine commands: - python3 -c "print(6 * 7)" - - name: algo2 + - name: pairingheap image: gcc:12.2.0 commands: - - cd algo2 + - cd algo2/pairingheap - gcc -o main pairingheap.c - ./main - name: radixheap diff --git a/algo2/pairingheap.c b/algo2/pairingheap/pairingheap.c similarity index 100% rename from algo2/pairingheap.c rename to algo2/pairingheap/pairingheap.c diff --git a/algo2/radixheap/radixheap.c b/algo2/radixheap/radixheap.c index e136e0a..d4b5b47 100644 --- a/algo2/radixheap/radixheap.c +++ b/algo2/radixheap/radixheap.c @@ -1,5 +1,191 @@ +#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() { - printf("Hello, radix heap!\n"); + 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); }