commit 590cd75d85b342a63e26def1478701b31f38a5d5
Author: olikru <olikru@tkruger.se>
Date: Mon, 8 Jan 2024 15:09:47 +0100
initial
Diffstat:
| A | Makefile | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
| A | README | | | 5 | +++++ |
| A | TODO | | | 2 | ++ |
| A | fheap.c | | | 249 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | fheap.h | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
| A | test_fheap.c | | | 8 | ++++++++ |
6 files changed, 344 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,40 @@
+.SUFFIXES: .c .o .so
+CC=clang
+CFLAGS+=-std=c99 -pedantic -Wall -Werror -Wstrict-prototypes
+CFLAGS+=-Wmissing-prototypes -Wmissing-declarations -Wshadow
+CFLAGS+=-Wpointer-arith -Wcast-qual -Wsign-compare
+CFLAGS+=-O2 -g
+CFLAGS+=-fstack-protector-all -Wtype-limits -fno-common
+CFLAGS+=-fno-builtin
+CFLAGS+=-I/usr/local/include
+
+INSTALL_PATH=$(HOME)/.local
+BUILD=build
+
+TEST_SOURCE=test_fheap.c
+HEADER=fheap.h
+OBJS=fheap.o
+SHARED=fheap.so
+LIBSHARED=libfheap.so
+
+all: build $(OBJS) $(SHARED) test
+
+.c.o:
+ $(CC) $(CFLAGS) -c $< -o $(BUILD)/$@
+
+.o.so:
+ $(CC) -shared -fPIC $(BUILD)/$< -o $(BUILD)/$@ $(LFLAGS)
+
+test: $(TEST_SOURCE)
+ $(CC) $(CFLAGS) -o $(BUILD)/test $(TEST_SOURCE) $(BUILD)/$(OBJS) $(LFLAGS)
+
+build:
+ mkdir -p $(BUILD)
+
+install:
+ cp $(BUILD)/$(SHARED) $(INSTALL_PATH)/lib/$(LIBSHARED)
+ chmod 644 $(INSTALL_PATH)/lib/$(LIBSHARED)
+ cp $(HEADER) $(INSTALL_PATH)/include/
+
+clean:
+ rm -rf $(BUILD)
diff --git a/README b/README
@@ -0,0 +1,5 @@
+fheap
+=====
+
+Fibonacci heap implementation (a type of priority queue) that uses
+uint64_t's as "keys"/"values". Based on the CLRS description.
diff --git a/TODO b/TODO
@@ -0,0 +1,2 @@
+* Implement unit tests
+* Documentation
diff --git a/fheap.c b/fheap.c
@@ -0,0 +1,249 @@
+#include "fheap.h"
+
+void fnode_init(fnode_t *node, const uint64_t value, void *data) {
+ node->children = NULL;
+ node->parent = NULL;
+ node->left = node;
+ node->right = node;
+ node->nchildren = 0;
+ node->marked = 0;
+
+ node->value = value;
+ node->data = data;
+}
+
+void fnode_clear(fnode_t *node) {
+ // clear children recursively
+ fnode_t *c, *d;
+ size_t n = node->nchildren;
+ c = node->children;
+ size_t i;
+ for (i = 0; i < n; i++) {
+ d = c->right;
+ fnode_clear(c);
+ c = d;
+ }
+
+ free(node);
+}
+
+void fheap_init(fheap_t *heap) {
+ heap->min = NULL;
+ heap->head = NULL;
+ heap->n = 0;
+}
+
+void fheap_clear(fheap_t *heap) {
+ fnode_t *c = heap->head;
+ fnode_t *d = c->right;
+
+ while (d != c) {
+ fnode_t *t = d->right;
+ fnode_clear(d);
+ d = t;
+ }
+ fnode_clear(c);
+
+ heap->min = NULL;
+ heap->head = NULL;
+ heap->n = 0;
+}
+
+static inline void insert_leftof(fnode_t *x, fnode_t *y) {
+ fnode_t *x_left = x->left;
+ x->left = y;
+ y->parent = x->parent;
+ y->right = x;
+ y->left = x_left;
+ x_left->right = y;
+}
+
+fnode_t *fheap_insert(fheap_t *heap, const uint64_t value, void *data) {
+ fnode_t *nnode = malloc(sizeof(*nnode));
+
+ fnode_init(nnode, value, data);
+
+ if (heap->min == NULL) {
+ heap->head = nnode;
+ heap->min = nnode;
+ } else {
+ insert_leftof(heap->head, nnode);
+ if (nnode->value < (heap->min)->value) {
+ heap->min = nnode;
+ }
+ }
+
+ heap->n++;
+
+ return nnode;
+}
+
+static inline void remove_node(fnode_t *x) {
+ (x->left)->right = x->right;
+ (x->right)->left = x->left;
+}
+
+static inline void fheap_link(fheap_t *heap, fnode_t *y, fnode_t *x) {
+ remove_node(y);
+ if (heap->head == y)
+ heap->head = y->right;
+ if (x->children != NULL) {
+ insert_leftof(x->children, y);
+ } else {
+ x->children = y;
+ y->parent = x;
+ y->left = y;
+ y->right = y;
+ x->nchildren = 0;
+ }
+ x->nchildren++;
+ y->marked = 0;
+}
+
+static inline void consolidate(fheap_t *heap) {
+ size_t i, deg;
+ fnode_t *a[heap->n];
+
+ for (i = 0; i < heap->n; i++)
+ a[i] = NULL;
+
+ fnode_t *c = heap->head;
+ fnode_t *head_list[heap->n];
+ size_t nheads = 0;
+ do {
+ head_list[nheads] = c;
+ nheads++;
+ c = c->right;
+ } while (c != heap->head);
+
+ size_t max_deg = 0;
+
+ fnode_t *x, *y;
+ for (i = 0; i < nheads; i++) {
+ c = head_list[i];
+
+ deg = c->nchildren;
+ x = c;
+ while (a[deg] != NULL) {
+ if (x->value > a[deg]->value) {
+ y = x;
+ x = a[deg];
+ } else {
+ y = a[deg];
+ }
+
+ fheap_link(heap, y, x);
+
+ a[deg] = NULL;
+ deg++;
+ }
+
+ a[deg] = x;
+
+ if (deg > max_deg)
+ max_deg = deg;
+ }
+
+ heap->head = NULL;
+ heap->min = NULL;
+ for (i = 0; i < max_deg + 1; i++) {
+ if (a[i] != NULL) {
+ if (heap->head == NULL) {
+ heap->head = a[i];
+ heap->min = a[i];
+ a[i]->left = a[i];
+ a[i]->right = a[i];
+ } else {
+ insert_leftof(heap->head, a[i]);
+ if (a[i]->value < (heap->min)->value)
+ heap->min = a[i];
+ }
+ }
+ }
+}
+
+fnode_t *fheap_extract_min_node(fheap_t *heap) {
+ fnode_t *z = heap->min;
+ fnode_t *c, *d;
+ if (z != NULL) {
+ if (z->nchildren > 0) {
+ c = z->children;
+ do {
+ d = c->right;
+ c->parent = NULL;
+ insert_leftof(heap->head, c);
+ c = d;
+ } while (c != z->children);
+ z->children = NULL;
+ }
+
+ remove_node(z);
+
+ if (z == z->right) {
+ heap->min = NULL;
+ heap->head = NULL;
+ } else {
+ heap->min = z->right;
+ if (heap->head == z)
+ heap->head = z->right;
+ consolidate(heap);
+ }
+
+ heap->n--;
+ }
+
+ return z;
+}
+
+uint64_t fheap_extract_min(void **data, fheap_t *heap) {
+ fnode_t *z = fheap_extract_min_node(heap);
+
+ uint64_t value = z->value;
+ *data = z->data;
+
+ z->nchildren = 0;
+ z->children = NULL;
+ fnode_clear(z);
+
+ return value;
+}
+
+static inline void fheap_cut(fheap_t *heap, fnode_t *x, fnode_t *y) {
+ remove_node(x);
+ if (y->children == x) {
+ if (x->right == x) {
+ y->children = NULL;
+ } else {
+ y->children = x->right;
+ }
+ }
+ y->nchildren--;
+
+ insert_leftof(heap->head, x);
+ x->parent = NULL;
+ x->marked = 0;
+}
+
+static void fheap_cascading_cut(fheap_t *heap, fnode_t *y) {
+ fnode_t *z = y->parent;
+ if (z != NULL) {
+ if (y->marked == 0) {
+ y->marked = 1;
+ } else {
+ fheap_cut(heap, y, z);
+ fheap_cascading_cut(heap, z);
+ }
+ }
+}
+
+void fheap_decrease_value(fheap_t *heap, fnode_t *node, const uint64_t value) {
+ node->value = value;
+ fnode_t *y = node->parent;
+ if (y != NULL && node->value < y->value) {
+ fheap_cut(heap, node, y);
+ fheap_cascading_cut(heap, y);
+ }
+
+ if (node->value < (heap->min)->value)
+ heap->min = node;
+}
diff --git a/fheap.h b/fheap.h
@@ -0,0 +1,40 @@
+#ifndef FHEAP_H
+#define FHEAP_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct fnode_struct {
+ uint64_t value;
+ void *data;
+
+ struct fnode_struct *parent;
+ struct fnode_struct *children;
+ size_t nchildren;
+ uint64_t marked;
+
+ struct fnode_struct *left;
+ struct fnode_struct *right;
+} fnode_t;
+
+typedef struct {
+ size_t n;
+ fnode_t *min;
+ fnode_t *head;
+} fheap_t;
+
+void fnode_init(fnode_t *node, const uint64_t value, void *data);
+void fnode_clear(fnode_t *node);
+
+void fheap_init(fheap_t *heap);
+void fheap_clear(fheap_t *heap);
+
+fnode_t *fheap_insert(fheap_t *heap, const uint64_t value, void *data);
+fnode_t *fheap_extract_min_node(fheap_t *heap);
+uint64_t fheap_extract_min(void **data, fheap_t *heap);
+
+void fheap_decrease_value(fheap_t *heap, fnode_t *node, const uint64_t value);
+
+#endif
diff --git a/test_fheap.c b/test_fheap.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include "fheap.h"
+
+int main() {
+ printf("test unimplemented\n");
+}