二叉堆算法实现

参考博客:
数据结构与算法系列 目录
二叉堆(一)之 图文解析 和 C语言的实现
libhv heap.h实现

二叉堆的算法实现,网上大多都是使用数组实现的。具体可以参考二叉堆(一)之 图文解析 和 C语言的实现。下面是基于树实现的二叉堆(libhv源码

#ifndef HV_HEAP_H_
#define HV_HEAP_H_

#include <assert.h> // for assert
#include <stddef.h> // for NULL

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 // HV_HEAP_H_

heap的使用:

int nindex = 0;
struct MyHeapNode
{
	MyHeapNode()
	{
		memset(&node, 0, sizeof(node));
		val = ++nindex;
	}
	struct heap_node node;
	int val;
};

int my_heap_compare(const struct heap_node* lhs, const struct heap_node* rhs)
{
	MyHeapNode *mylNode = (MyHeapNode *)lhs;
	MyHeapNode *myrNode = (MyHeapNode *)rhs;
	return myrNode->val < mylNode->val ? 1 : 0;
}

struct heap myheap;

heap_init(&myheap, my_heap_compare);

heap_insert(&myheap, (heap_node *)(new MyHeapNode()));
heap_insert(&myheap, (heap_node *)(new MyHeapNode()));
heap_insert(&myheap, (heap_node *)(new MyHeapNode()));
heap_insert(&myheap, (heap_node *)(new MyHeapNode()));
heap_insert(&myheap, (heap_node *)(new MyHeapNode()));

MyHeapNode *mylNode = (MyHeapNode *)myheap.root;
//删除堆顶
heap_dequeue(&myheap);

关于该算法原理可以参考libhv heap.h实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Dijkstra算法是一种用于解决单源最短路径问题的算法。它通过从起点开始,逐步找到当前最短路径的节点,并不断更新其他节点的距离值,最终得到起点到所有其他节点的最短距离。Dijkstra算法的基本思想是使用贪心策略,选择当前路径最短的节点作为中间节点,并以此为基础不断更新其他节点的距离值,直到遍历完所有节点。 二叉堆是一种用于实现优先队列的数据结构,它可以高效地进行插入和删除操作。二叉堆是一个完全二叉树,且父节点的值小于等于其子节点的值。在Dijkstra算法中,使用二叉堆可以有效地选取下一个最短路径的节点,从而提高算法的效率。 大堆是一种特殊的二叉堆,它满足父节点的值大于等于其子节点的值。大堆的特点是根节点的值最大,因此可以用来实现最大优先队列。在Dijkstra算法中,使用大堆可以高效地选择路径最短的节点,因为每次选择的节点都是当前距离最短的节点,所以大堆能够快速选出下一个待更新的节点,并更新其距离值。 综上所述,Dijkstra算法通过使用二叉堆这种数据结构,特别是大堆,能够高效地寻找最短路径问题的解答。通过Dijkstra算法,我们可以得到从起点到其他所有节点的最短路径,这在很多实际问题中具有重要的应用价值。 ### 回答2: dijkstra算法是一种解决图最短路径问题的算法,通过计算从起点到其他顶点的最短路径权值来找到最短路径。该算法的核心思想是以起点为中心,逐步扩展到其他顶点,每次选择当前最短路径的顶点并更新其邻居的最短路径权值。最后,当所有顶点都被扩展并更新完毕时,即可得到从起点到其他顶点的最短路径。 二叉堆是一种特殊的堆数据结构,它是通过二叉树来实现的,具有以下性质:任意节点的值都大于(或小于)其子节点的值。在dijkstra算法中,可以使用二叉堆来维护每个顶点的最短路径权值。通过使用二叉堆,可以高效地选择当前最短路径的顶点,并更新其邻居的最短路径权值。另外,使用二叉堆可以将插入和删除操作的时间复杂度控制在O(log n)级别。 大堆是一种堆排序中的概念,具体指堆中每个节点的值都不小于其子节点的值。在二叉堆中,大堆的概念可以用来实现最大堆。与二叉堆类似,最大堆也可以用来实现dijkstra算法中的优先队列,用于高效地选择当前最短路径的顶点。在使用最大堆进行元素插入或删除操作时,也可以保持时间复杂度在O(log n)级别。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值