|
@@ -0,0 +1,172 @@
|
|
|
|
|
+#ifndef HW_HEAP_H_
|
|
|
|
|
+#define HW_HEAP_H_
|
|
|
|
|
+
|
|
|
|
|
+#include <assert.h>
|
|
|
|
|
+
|
|
|
|
|
+#include "hdef.h"
|
|
|
|
|
+
|
|
|
|
|
+struct heap_node {
|
|
|
|
|
+ struct heap_node* parent;
|
|
|
|
|
+ struct heap_node* left;
|
|
|
|
|
+ struct heap_node* right;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+typedef int (*heap_compare_fn)(const struct heap_node* lhs, const struct heap_node* rhs);
|
|
|
|
|
+struct heap {
|
|
|
|
|
+ struct heap_node* root;
|
|
|
|
|
+ int nelts; // if compare is less_than, root is min of heap
|
|
|
|
|
+ // if compare is larger_than, root is max of heap
|
|
|
|
|
+ heap_compare_fn compare;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+static inline void heap_init(struct heap* heap, heap_compare_fn fn) {
|
|
|
|
|
+ heap->root = NULL;
|
|
|
|
|
+ heap->nelts = 0;
|
|
|
|
|
+ heap->compare = fn;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// replace s with r
|
|
|
|
|
+static inline void heap_replace(struct heap* heap, struct heap_node* s, struct heap_node* r) {
|
|
|
|
|
+ // s->parent->child, s->left->parent, s->right->parent
|
|
|
|
|
+ if (s->parent == NULL) heap->root = r;
|
|
|
|
|
+ else if (s->parent->left == s) s->parent->left = r;
|
|
|
|
|
+ else if (s->parent->right == s) s->parent->right = r;
|
|
|
|
|
+
|
|
|
|
|
+ if (s->left) s->left->parent = r;
|
|
|
|
|
+ if (s->right) s->right->parent = r;
|
|
|
|
|
+ if (r) {
|
|
|
|
|
+ //*r = *s;
|
|
|
|
|
+ r->parent = s->parent;
|
|
|
|
|
+ r->left = s->left;
|
|
|
|
|
+ r->right = s->right;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static inline void heap_swap(struct heap* heap, struct heap_node* parent, struct heap_node* child) {
|
|
|
|
|
+ assert(child->parent == parent && (parent->left == child || parent->right == child));
|
|
|
|
|
+ struct heap_node* pparent = parent->parent;
|
|
|
|
|
+ struct heap_node* lchild = child->left;
|
|
|
|
|
+ struct heap_node* rchild = child->right;
|
|
|
|
|
+ struct heap_node* sibling = NULL;
|
|
|
|
|
+
|
|
|
|
|
+ if (pparent == NULL) heap->root = child;
|
|
|
|
|
+ else if (pparent->left == parent) pparent->left = child;
|
|
|
|
|
+ else if (pparent->right == parent) pparent->right = child;
|
|
|
|
|
+
|
|
|
|
|
+ if (lchild) lchild->parent = parent;
|
|
|
|
|
+ if (rchild) rchild->parent = parent;
|
|
|
|
|
+
|
|
|
|
|
+ child->parent = pparent;
|
|
|
|
|
+ if (parent->left == child) {
|
|
|
|
|
+ sibling = parent->right;
|
|
|
|
|
+ child->left = parent;
|
|
|
|
|
+ child->right = sibling;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ sibling = parent->left;
|
|
|
|
|
+ child->left = sibling;
|
|
|
|
|
+ child->right = parent;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (sibling) sibling->parent = child;
|
|
|
|
|
+
|
|
|
|
|
+ parent->parent = child;
|
|
|
|
|
+ parent->left = lchild;
|
|
|
|
|
+ parent->right = rchild;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static inline void heap_insert(struct heap* heap, struct heap_node* node) {
|
|
|
|
|
+ // get last => insert node => sift up
|
|
|
|
|
+ // 0: left, 1: right
|
|
|
|
|
+ int path = 0;
|
|
|
|
|
+ int n,d;
|
|
|
|
|
+ ++heap->nelts;
|
|
|
|
|
+ // traverse from bottom to up, get path of last node
|
|
|
|
|
+ for (d = 0, n = heap->nelts; n >= 2; ++d, n>>=1) {
|
|
|
|
|
+ path = (path << 1) | (n & 1);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // get last->parent by path
|
|
|
|
|
+ struct heap_node* parent = heap->root;
|
|
|
|
|
+ while(d > 1) {
|
|
|
|
|
+ parent = (path & 1) ? parent->right : parent->left;
|
|
|
|
|
+ --d;
|
|
|
|
|
+ path >>= 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // insert node
|
|
|
|
|
+ node->parent = parent;
|
|
|
|
|
+ if (parent == NULL) heap->root = node;
|
|
|
|
|
+ else if (path & 1) parent->right = node;
|
|
|
|
|
+ else parent->left = node;
|
|
|
|
|
+
|
|
|
|
|
+ // sift up
|
|
|
|
|
+ if (heap->compare) {
|
|
|
|
|
+ while (node->parent && heap->compare(node, node->parent)) {
|
|
|
|
|
+ heap_swap(heap, node->parent, node);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static inline void heap_remove(struct heap* heap, struct heap_node* node) {
|
|
|
|
|
+ if (heap->nelts == 0) return;
|
|
|
|
|
+ // get last => replace node with last => sift down and sift up
|
|
|
|
|
+ // 0: left, 1: right
|
|
|
|
|
+ int path = 0;
|
|
|
|
|
+ int n,d;
|
|
|
|
|
+ // traverse from bottom to up, get path of last node
|
|
|
|
|
+ for (d = 0, n = heap->nelts; n >= 2; ++d, n>>=1) {
|
|
|
|
|
+ path = (path << 1) | (n & 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ --heap->nelts;
|
|
|
|
|
+
|
|
|
|
|
+ // get last->parent by path
|
|
|
|
|
+ struct heap_node* parent = heap->root;
|
|
|
|
|
+ while(d > 1) {
|
|
|
|
|
+ parent = (path & 1) ? parent->right : parent->left;
|
|
|
|
|
+ --d;
|
|
|
|
|
+ path >>= 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // replace node with last
|
|
|
|
|
+ struct heap_node* last = NULL;
|
|
|
|
|
+ if (parent == NULL) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (path & 1) {
|
|
|
|
|
+ last = parent->right;
|
|
|
|
|
+ parent->right = NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ last = parent->left;
|
|
|
|
|
+ parent->left = NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (last == NULL) {
|
|
|
|
|
+ if (heap->root == node) {
|
|
|
|
|
+ heap->root = NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ heap_replace(heap, node, last);
|
|
|
|
|
+ node->parent = node->left = node->right = NULL;
|
|
|
|
|
+
|
|
|
|
|
+ if (!heap->compare) return;
|
|
|
|
|
+ struct heap_node* v = last;
|
|
|
|
|
+ struct heap_node* est = NULL;
|
|
|
|
|
+ // sift down
|
|
|
|
|
+ while (1) {
|
|
|
|
|
+ est = v;
|
|
|
|
|
+ if (v->left) est = heap->compare(est, v->left) ? est : v->left;
|
|
|
|
|
+ if (v->right) est = heap->compare(est, v->right) ? est : v->right;
|
|
|
|
|
+ if (est == v) break;
|
|
|
|
|
+ heap_swap(heap, v, est);
|
|
|
|
|
+ }
|
|
|
|
|
+ // sift up
|
|
|
|
|
+ while (v->parent && heap->compare(v, v->parent)) {
|
|
|
|
|
+ heap_swap(heap, v->parent, v);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static inline void heap_dequeue(struct heap* heap) {
|
|
|
|
|
+ heap_remove(heap, heap->root);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#endif // HW_HEAP_H_
|