设为首页 加入收藏

TOP

C 数据结构堆(二)
2018-12-05 14:12:25 】 浏览:425
Tags:数据结构
的代码就

很轻松出手了

//
// heap_insert - 堆插入数据
// h        : 堆对象
// node     : 操作对象
// return   : void
//
inline void 
heap_insert(heap_t h, void * node) {
    heap_expand(h);
    up(h->fcmp, node, h->data, h->len++);
}

//
// heap_top - 查看堆顶结点数据
// h        : 堆对象
// return   : 堆顶节点
//
inline void * 
heap_top(heap_t h) {
    return h->len <= 0 ? NULL : *h->data;
}

//
// heap_top - 摘掉堆顶结点数据
// h        : 堆对象
// return   : 返回堆顶节点
//
inline void * 
heap_pop(heap_t h) {
    void * node = heap_top(h);
    if (node && --h->len > 0) {
        // 尾巴节点一定比小堆顶节点大, 那么要下沉
        h->data[0] = h->data[h->len];
        down(h->fcmp, h->data, h->len, 0);
    }
    return node;
}

看完上面代码可以再回看下 down 和 up 代码布局. 是不是堆节点调整全部技巧已经了然于胸 ~

随后我们介绍堆删除任意节点大致算法思路

  1' 循环遍历, 找到要删除节点

  2' 如果删除后堆空, 或者删除的是最后节点, 那直接搞定

  3' 最后节点复制到待删除节点位置处

  4' 最后节点和待删除节点权值相等, 不调整节点关系

  5' 最后节点比待删除节点权值大, 向下调整节点关系(基于小顶堆设计)

  6' 最后节点比待删除节点权值小, 向上调整节点关系

从上可以看出堆删除节点算法复杂度是 O(n) + O(logn) = O(n). 请欣赏具体代码

//
// heap_remove - 堆删除数据
// h        : 堆对象
// arg      : 操作参数
// fcmp     : 比较行为, 规则 fcmp() == 0
// return   : 找到的堆节点
//
void * 
heap_remove(heap_t h, void * arg, cmp_f fcmp) {
    if (h == NULL || h->len <= 0)
        return NULL;

    // 开始查找这个节点
    unsigned i = 0;
    fcmp = fcmp ? fcmp : h->fcmp;
    do {
        void * node = h->data[i];
        if (fcmp(arg, node) == 0) {
            if (--h->len > 0 && h->len != i) {
                // 尾巴节点和待删除节点比较
                int ret = h->fcmp(h->data[h->len], node);

                // 小顶堆, 新的值比老的值小, 那么上浮
                if (ret < 0)
                    up(h->fcmp, h->data[h->len], h->data, i);
                else if (ret > 0) {
                    // 小顶堆, 新的值比老的值大, 那么下沉
                    h->data[i] = h->data[h->len];
                    down(h->fcmp, h->data, h->len, i);
                }
            }

            return node;
        }
    } while (++i < h->len);

    return NULL;
}

到这堆数据结构基本代码都已经搞定. 开始写写测试用例跑跑

#include "heap.h"
#include <stdio.h>

struct node {
    int value;
};

static inline int node_cmp(const struct node * l, const struct node * r) {
    return l->value - r->value;
}

static void heap_print(heap_t h) {
    struct heap {
        cmp_f   fcmp;       // 比较行为
        unsigned len;       // heap 长度
        unsigned cap;       // heap 容量
        void ** data;       // 数据节点数组
    } * x = (struct heap *)h;

    // 数据打印for (unsigned i = 0; i < x->len; ++i) {
        struct node * node = x->data[i];
        printf("%d ", node->value);
    }
    putchar('\n');
}

int main() {
    heap_t h = heap_create(node_cmp);
    struct node a[] = { { 53 }, { 17 }, { 78 }, { 9 }, { 45 }, { 65 }, { 87 }, { 23} };
    for (int i = 0; i < sizeof a / sizeof *a; ++i)
        heap_insert(h, a + i);

    heap_print(h);

    // 数据打印
    struct node * node;
    while ((node = heap_pop(h))) {
        printf("%d ", node->value);
    }
    putchar('\n');

    // 重新插入数据
    for (int i = 0; i < sizeof a / sizeof *a; ++i)
        heap_insert(h, a + i);

    // 删除操作 - 下沉
    heap_remove(h, &(struct node){ 17 }, NULL);
    heap_print(h);

    // 插入操作
    heap_insert(h, &(struct node){ 17 });
    heap_print(h);

    // 删除操作 - 上浮
    heap_remove(h, &(struct node){ 78 }, NULL);
    heap_print(h);

    heap_delete(h, NULL);
    return 0;
}

最终运行结果如下

 

后续堆相关代码变化, 可以参照  heap - https://github.com/wangzhione/structc/blob/master/structc/struct/heap.c

说到引用 github 想起一个 git 好用配置安利给大家 ~ 从此 git ll 就活了.

git config --global color.diff auto
git config --global color.status auto git config --global color.branch auto git config --global color.interactive auto git config --global alias.ll "log --graph --all --pretty=format:'%C
首页 上一页 1 2 3 4 5 6 下一页 尾页 2/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇关于单链表的排序问题 下一篇pow函数(数学次方)在c语言的用..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目