zoukankan      html  css  js  c++  java
  • 32、STL中的heap的实现

    heap(堆)并不是STL的容器组件,是priority queue(优先队列)的底层实现机制,因为binary max heap(大根堆)总是最大值位于堆的根部,优先级最高。

    binary heap本质是一种complete binary tree(完全二叉树),整棵binary tree除了最底层的叶节点之外,都 是填满的,但是叶节点从左到右不会出现空隙,如下图所示就是一颗完全二叉树

    完全二叉树内没有任何节点漏洞,是非常紧凑的,这样的一个好处是可以使用array来存储所有的节点, 因为当其中某个节点位于$i$处,其左节点必定位于$2i$处,右节点位于$2i+1$处,父节点位于$i/2$(向 下取整)处。这种以array表示tree的方式称为隐式表述法。

    因此我们可以使用一个array和一组heap算法来实现max heap(每个节点的值大于等于其子节点的值)和 min heap(每个节点的值小于等于其子节点的值)。由于array不能动态的改变空间大小,用vector代替 array是一个不错的选择。

    那heap算法有哪些?常见有的插入、弹出、排序和构造算法,下面一一进行描述。

    push_heap插入算法

    由于完全二叉树的性质,新插入的元素一定是位于树的最底层作为叶子节点,并填补由左至右的第一个 空格。事实上,在刚执行插入操作时,新元素位于底层vector的end()处,之后是一个称为percolate up(上溯)的过程,举个例子如下图:

    新元素50在插入堆中后,先放在vector的end()存着,之后执行上溯过程,调整其根结点的位置,以便满 足max heap的性质,如果了解大根堆的话,这个原理跟大根堆的调整过程是一样的。

    pop_heap算法

     heap的pop操作实际弹出的是根节点吗,但在heap内部执行pop_heap时,只是将其移动到vector的最后位 置,然后再为这个被挤走的元素找到一个合适的安放位置,使整颗树满足完全二叉树的条件。这个被挤 掉的元素首先会与根结点的两个子节点比较,并与较大的子节点更换位置,如此一直往下,直到这个被 挤掉的元素大于左右两个子节点,或者下放到叶节点为止,这个过程称为percolate down(下溯)。举个 例子:

    根节点68被pop之后,移到了vector的最底部,将24挤出,24被迫从根节点开始与其子节点进行比较,直 到找到合适的位置安身,需要注意的是pop之后元素并没有被移走,如果要将其移走,可以使用 pop_back()。

     sort算法

    一言以蔽之,因为pop_heap可以将当前heap中的最大值置于底层容器vector的末尾,heap范围减1,那么 不断的执行pop_heap直到树为空,即可得到一个递增序列。

    make_heap算法

    将一段数据转化为heap,一个一个数据插入,调用上面说的两种percolate算法即可。

    代码实测:

    #include <iostream>
    #include <algorithm>
    #include <vector>
    using namespace std;
    int main()
    {
    vector<int> v = { 0,1,2,3,4,5,6 };
    make_heap(v.begin(), v.end()); //以vector为底层容器
    for (auto i : v)
    {
    cout << i << " "; // 6 4 5 3 1 0 2
    }
    cout << endl;
    v.push_back(7);
    push_heap(v.begin(), v.end());
    for (auto i : v)
    {
    cout << i << " "; // 7 6 5 4 1 0 2 3
    }
    cout << endl;
    pop_heap(v.begin(), v.end());
    for (auto i : v)
    {
    cout << i << " "; // 6 4 5 3 1 0 2 7
    }
    cout << endl;
    cout << v.back() << endl; // 7
    v.pop_back();
    for (auto i : v)
    {
    cout << i << " "; // 6 4 5 3 1 0 2
    }
    cout << endl;
    sort_heap(v.begin(), v.end());
    for (auto i : v)
    {
    cout << i << " "; // 0 1 2 3 4 5 6
    }
    return 0;
    }
  • 相关阅读:
    mysql 函数 存储过程 事件(event) job 模板
    protobuf 无proto 解码 decode 语言 java python
    mitmproxy fiddler 抓包 填坑
    android adb 常用命令
    android机器人 模拟 踩坑过程
    RabbitMQ添加新用户并支持远程访问
    Windows下RabbitMQ安装及配置
    Java mybatis mysql 常用数据类型对应关系
    easyExcel 踩坑
    linux防火墙查看状态firewall、iptable
  • 原文地址:https://www.cnblogs.com/crbhf/p/15072842.html
Copyright © 2011-2022 走看看