STL中的heap

1、heap的概念
heap(堆)就是用数组实现的二叉树,所以它没有使用父指针或者子指针。堆根据“堆属性”来排序,“堆属性”决定了树中节点的位置。堆的常用方法:构建优先队列、支持堆排序、快速找出一个集合中的最小值(或者最大值)。

(1)heap属性
1)堆属性分为两种:最大堆和最小堆。在最大堆中,父节点的值比每一个节点的值都要大。在最小堆中,父节点的值比每一个子节点的值都要小。
2)heap没有迭代器
heap的所有元素都必须遵循特别的complete
binary tree排序规则,所以heap不提供遍历功能,也不提供迭代器。

(2)binary heap
binary heap就是一种complete binary tree(完全二叉树),即:整棵binary
tree除了最底层的叶节点之外是填满的,而最底层的叶节点由左至右不得有空隙,如下图所示。STL中的heap_第1张图片
(3)堆和普通树的区别
1)节点的顺序
在二叉搜索树中,左子节点必须比父节点小,右子节点必须比父节点大。但是,在堆中并非如此。在最大堆中两个子节点都必须比父节点小,而在最小堆中,它们都必须比父节点大。
2)内存占用
普通树占用的内存空间比它们存储的数据要多,必须为节点对象以及左右子节点指针分配足够的内存。堆仅仅使用一个数据来村塾数组,且不使用指针。

2、heap算法
(1)push_heap算法
push_heap算法要求新加入的元素一定要放在最下一层作为叶节点,,并填补在由左至右的第一个空格,也就是把新元素插入在底层vector的end()处,如下图所示。STL中的heap_第2张图片
(2)pop_heap算法
1)在max-heap中,最大值必然在根节点,pop操作取走根节点之后,为了满足complete binary tree的条件,需要将最下一层最右边的叶节点拿掉,而取走的根节点其实是移至底部容器vector的最后一个元素。
2)为满足max-heap的条件,执行下溯程序:将根节点(最大值被取走后形成一个“洞”)填入失去生存空间的叶节点值,再将它拿来和其两个子节点比较键值,并与较大子节点对调位置,直到这个“洞”的键值大于左右两个子节点,或者到下放至叶节点为止。如下图所示:
STL中的heap_第3张图片
注意:pop_heap之后,最大值只是被置放在底部容器的最尾端,尚未被取走。如果要取其值,可使用底部容器(vector)所提供的back()操作函数。如果要移除它,可使用底部容器(vector)所提供的pop_back()操作函数。

(3)sort_heap算法
每次使用pop_heap可获得heap中键值最大的元素,如果持续对整个heap做pop_heap操作,每次将操作范围从后向前缩减一个元素,因为pop_heap会把键值最大的元素放在底部容器的最尾端,当整个程序执行完毕时,就形成一个递增序列,如下图所示。
STL中的heap_第4张图片
STL中的heap_第5张图片
STL中的heap_第6张图片
注意:排序后,原来的heap就不再是一个合法的heap。

(4)make_heap算法
这个算法用来将一段现有的数据转化为一个heap。

3、heap测试实例
【例1】底层以vector完成

#include
#include
#include

using namespace std;

void TestHeap1()
{
    int arr[9] = { 0, 1, 2, 3, 4, 8, 9, 3, 5 };
    vector<int> v1(arr, arr + 9);
    cout << "vector data:";
    for (int i = 0; i < v1.size(); i++)
    {
        cout << v1[i] << " ";
    }
    cout << endl;

    //make_heap
    make_heap(v1.begin(), v1.end());
    cout << "make heap后:";
    for (int i = 0; i < v1.size(); i++)
    {
        cout << v1[i] << " ";
    }
    cout << endl;

    //push_heap
    v1.push_back(7);
    push_heap(v1.begin(), v1.end());
    cout << "push 7 heap后:";
    for (int i = 0; i < v1.size(); i++)
    {
        cout << v1[i] << " ";
    }
    cout << endl;

    //pop_heap
    pop_heap(v1.begin(), v1.end());
    cout << "pop heap:";
    cout << v1.back() << endl; //最大值9被放在vector的最尾端,但是没有取走
    v1.pop_back();
    cout << "pop back后:";
    for (int i = 0; i < v1.size(); i++)
    {
        cout << v1[i] << " ";
    }
    cout << endl;

    //sort_heap
    sort_heap(v1.begin(), v1.end());
    cout << "sort heap后:";
    for (int i = 0; i < v1.size(); i++)
    {
        cout << v1[i] << " ";
    }
    cout << endl;
}

int main()
{
    TestHeap1();
    system("pause");
    return 0;
}

运行结果为:
STL中的heap_第7张图片
【例2】底层以array完成

#include
#include
 
using namespace std;
 
void TestHeap2()
{
    int arr[9] = { 0, 1, 2, 3, 4, 8, 9, 3, 5 };
    make_heap(arr, arr + 9);
    cout << "make heap后:";
    for (int i = 0; i < 9; i++)
    {
        cout << arr[i] << " ";
    }
    cout << endl;

    //sort_heap
    sort_heap(arr, arr + 9);
    cout << "sort make后:";
    for (int i = 0; i < 9; i++)
    {
        cout << arr[i] << " ";
    }
    cout << endl;
    //经过排序之后的heap,不再是个合法的heap

    //重新再做一个heap
    make_heap(arr, arr + 9);
    cout << "再一次make heap后:";
    for (int i = 0; i < 9; i++)
    {
        cout << arr[i] << " ";
    }
    cout << endl;
 
    //pop_heap
    pop_heap(arr, arr + 9);
    cout << "pop heap后,查看arr[8]的值:";
    cout << arr[8] << endl;
}
 
int main()
{
    TestHeap2();
    system("pause");
    return 0;
}

运行结果为:
STL中的heap_第8张图片

你可能感兴趣的:(C++)