【STL】Heap算法——push_heap、pop_heap、sort_heap、make_heap

迷南。 2022-07-15 10:30 302阅读 0赞

参考文章:《STL源码剖析》 侯捷 译;

C++STL算法提供make_heap, push_heap和pop_heap等算法,它们作用于随机存取迭代器。它们将迭代器当做数组的引用,并做出array-to-heap的转换。STL中默认这个算法为最大堆(max_heap)。

make_heap

make_heap 的功能是将一段现有的数据转化成一个heap(堆)。默认状态下,它会生成一个最大堆结构,我们也可以自己定义为最大堆或者最小堆。我们先看它的定义:

定义1:(默认状态)

  1. template <class RandomAccessIterator>//模板参数
  2. void make_heap ( RandomAccessIterator first, RandomAccessIterator last );
  3. 我们可以看到,定义1有两个参数,参数为模板类型的迭代器。作用为当我们传一个左闭右开区间\[first,last)时,它会自动把这个区间的数据转化成一个最大堆。

定义2:(传compare)

  1. template <class RandomAccessIterator, class Compare>
  2. void make_heap ( RandomAccessIterator first, RandomAccessIterator last,Compare comp );
  3. 定义2里面多了一个模板参数,用于我们给它传一个比较类型。用这个比较类型决定实现最大堆还是最小堆。以下的push\_heappop\_heapsort\_heap都有两种定义,区别于make\_heap相同。

push_heap

定义1:

  1. template <class RandomAccessIterator>
  2. void push_heap ( RandomAccessIterator first, RandomAccessIterator last );
  3. 定义2
  4. template <class RandomAccessIterator, class Compare>
  5. void push_heap ( RandomAccessIterator first, RandomAccessIterator last,Compare comp );

push_heap的功能是往‘堆’中插入一个数据。但是,它的默认前提是这个区间[first,last)已经满足堆结构,并且要插入的数据已经插入到堆的最后即区间的最后一个位置。为什么呢?因为STL库提供的push_heap算法并没有插入元素,仅仅是完成插入元素后的调整工作,将插入元素后的区间重新恢复堆结构。无论插入几个数据,调用push_heap前都必须将数据先插入到区间中。

图解:

20161113191057687

下面看一个它的例子:

  1. vector<int> a = { 3, 6, 2, 1, 7, 4, 9, 5 };
  2. make_heap(a.begin(), a.end());//前提①,建堆,使区间满足堆结构
  3. a.push_back(20);//前提②,要插入数据已经插入
  4. push_heap(a.begin(), a.end());//push_heap做出调整
  5. for (int i = 0; i < a.size(); ++i)
  6. {
  7. cout << a[i] << " ";
  8. }
  9. cout << endl;

结果:

20161113192148498

pop_heap

定义1:

  1. template <class RandomAccessIterator>
  2. void pop_heap ( RandomAccessIterator first, RandomAccessIterator last );
  3. 定义2
  4. template <class RandomAccessIterator, class Compare>
  5. void pop_heap ( RandomAccessIterator first, RandomAccessIterator last,Compare comp );
  6. pop\_head实现的同样是调整工作,不过它是删除前的调整。当调用pop\_head后,我们再将区间的最后一个元素pop掉。为什么要pop最后一个元素呢?因为pop\_head完成的工作就是将堆顶的元素与最后一个元素交换,再执行调整程序,将除了区间最后一个元素(此时已经交换)的所有元素重新恢复堆结构。 最后记住。每pop一个元素,下一次操作时last要减1。(区间要缩小1)

图解:

20161113190927340

例子:

  1. vector<int> a = { 3, 6, 2, 1, 7, 4, 9, 5 };
  2. make_heap(a.begin(),a.end());//前提①,建堆,使区间满足堆结构
  3. a.push_back(20);//前提②,要插入数据已经插入
  4. push_heap(a.begin(), a.end());//push_heap做出调整
  5. pop_heap(a.begin(), a.end());
  6. a.pop_back();
  7. for (int i = 0; i < a.size(); ++i)
  8. {
  9. cout << a[i] << " ";
  10. }
  11. cout << endl;

结果:(与上图结果做比较)

20161113192246233

sort_heap

定义1:

  1. template <class RandomAccessIterator>
  2. void sort_heap ( RandomAccessIterator first, RandomAccessIterator last );

定义2:

  1. template <class RandomAccessIterator, class Compare>
  2. void sort_heap ( RandomAccessIterator first, RandomAccessIterator last,Compare comp);

当我们学会了使用pop_heap后,你就会很容易理解sort_heap的实现原理了。从上我们可以知道,我们每执行一次pop_heap,就会有一个最大的元素到区间的最后,sort_heap就是多次调用pop _heap,每次将堆顶元素(最大元素)与最后元素发生交换。last—(区间缩小1),重复以上工作,直到区间只剩下1个元素。最后就完成了排序。

图解:

20161113191747501

20161113191846877

20161113191938776

例子:

  1. vector<int> a = { 3, 6, 2, 1, 7, 4, 9, 5 };
  2. make_heap(a.begin(),a.end());//前提①,建堆,使区间满足堆结构
  3. a.push_back(20);//前提②,要插入数据已经插入
  4. push_heap(a.begin(), a.end());//push_heap做出调整
  5. pop_heap(a.begin(), a.end());
  6. a.pop_back();
  7. sort_heap(a.begin(), a.end());
  8. for (int i = 0; i < a.size(); ++i)
  9. {
  10. cout << a[i] << " ";
  11. }
  12. cout << endl;
  13. 结果:(与上图结果做比较)

20161113192504674

发表评论

表情:
评论列表 (有 0 条评论,302人围观)

还没有评论,来说两句吧...

相关阅读

    相关 算法-分治算法

    一、分治 1、定义:分治,也就是分而治之。 它的一般步骤是: ① 将原问题分解成若干个规模较小的子问题(子问题和原问题的结构一样,只是规模不一样)

    相关 算法-回溯算法

    一、回溯 1、定义:通过选择不同的岔路口来通往目的地(找到想要的结果) 每一步都选择一条路出发,`能进则进,不能进则退回上一步(回溯)`,换一条路再

    相关 算法】查找算法

    文章目录 二分查找并返回数据应该插入的位置 二分查找并返回数据应该插入的位置 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存

    相关 算法--排序算法

    首发网址:[算法--排序算法\_IT利刃出鞘的博客-CSDN博客][--_IT_-CSDN] 其他网址 [一文搞定十大经典排序算法(Java实现) - 简书][Java

    相关 算法 BF算法

    BF算法是字符匹配的一种算法,也称暴力匹配算法 算法思想: 从主串s1的pos位置出发,与子串s2第一位进行匹配 若相等,接着匹配后一位字符 若不相等,则返回到s