【问题标题】:Is there a maxheap in the C++ standard library?C++标准库中有maxheap吗?
【发布时间】:2019-12-07 19:44:50
【问题描述】:

我知道std::priority_queue 类实现了一个minheap。有没有办法将它用作最大堆?还是有替代的 Maxheap 结构?我知道我可以在带有 lambda 的 std::vector 上使用 std::make_heap() 函数来创建我自己的 Maxheap,但是使用诸如 std::pop_heap() 之类的函数很奇怪,我认为它们不容易使用。应该有一个更简单的方法,就像我认为的 min_heap(priority queue)。

【问题讨论】:

  • 在 STL 中,堆与实际的容器实现分离。看看std::make_heap。它允许您传递一个自定义比较器,在您的情况下可能是 std::greater<>{}
  • 是的,我一直在使用它,但是当我尝试删除元素时使用 pop_heap() 然后 pop_back() 感觉很奇怪,所以我认为可能有更好的选择。谢谢。
  • @lubgr 请注意,std::make_heap 和标准库中的所有堆算法/项都会生成最大堆,而不是最小堆。因此,std::greater<>{} 将构成最小堆。记住这一点的最简单方法是将堆实用程序想象成堆排序的实现细节。
  • @Justin 好点,我混淆了最小堆 - std::greater,最大堆 - std::less

标签: c++ priority-queue c++-standard-library standard-library max-heap


【解决方案1】:

关于std::priority_queue

可以提供用户提供的Compare 来更改排序,例如使用 std::greater<T> 会导致 最小元素 显示为 top()

由于std::less<T>Compare 模板参数的默认模板参数,因此默认情况下它已经是一个最大堆。如果你想要一个 min heap 代替(上面的引用建议),传递 std::greater<T> 而不是 std::less<T> 作为模板参数。

总结一下:

  • 最大堆:传递std::less<T>(这是默认模板参数)。
  • 最小堆:通过std::greater<T>

注意std::priority_queue 实际上是一个容器适配器(与数据结构相反)。它没有指定使用什么底层数据结构。但是,由于 push()pop()top() 操作的指定运行时复杂性,它很可能以堆的形式实现。

【讨论】:

  • 那么要创建一个最小堆,我的声明看起来像priority_queue<int, std::greater<int>> q; 对吗?在您链接的页面中,模板争论中还有一个向量,但我不明白其中的原因。
  • @OgiciBumKacar 是的。向量是底层容器。
  • @OgiciBumKacar 你应该使用std::priority_queue<int, std::vector<int>, std::greater<int> > q;
  • 为什么std::less<T>是一个最大堆对应的模板? std::greater<T> 不是更直观,因为数据类型 T 具有最大值的根节点具有 最高 优先级吗?
  • @E.Kaufman 在std::priority_queue 中,“最大”元素总是出现在顶部。然而,“最大”的含义取决于比较函数:它必须以这样一种方式定义,以便true 在其第一个参数之前返回(即, 它比它的第二个参数“小”。换句话说,如果比较函数的第二个参数比第一个参数“更大”,则比较函数必须返回true——即,当true 时,第二个参数将成为堆顶之前第一个论点确实如此。因此,如果使用std::less,堆对应一个max-heap
【解决方案2】:

简答

最大堆:

priority_queue<int> maxHeap; // NOTE: default is max heap

最小堆

priority_queue<int, vector<int> , greater<int>> minHeap;

标题和命名空间:

#include <vector>
#include <priority_queue>

using namespace std;

【讨论】:

    【解决方案3】:

    没有“堆”容器,就像没有“搜索树”,也没有“哈希图”(而不是后两者,有有序和无序的关联容器,它们实际上是使用这些数据结构实现的,因为没有其他数据结构可以满足为这些容器指定的要求)。

    一个容器适配器std::priority_queue,它可以适配一个SequenceContainer(std::vector默认适配),并提供与最大/最小堆相同的操作,并且可能在内部是实现为某种堆。

    还有std::make_heap 可用于在随机访问范围内强制执行最大堆属性。

    【讨论】:

    • 这真是让人毛骨悚然。标准要求容器的行为方式实际上只有一个 RB-Tree 可用于关联容器,无序容器需要是“散列映射”/“散列集”(尽管在非常非-最佳方式桶迭代器)。
    • @NathanOliver 你确定除了 RB-tree 没有其他平衡搜索树吗?使用它不一定有任何优势,但AVL树不能满足所有要求吗?无论如何,正如我所说,关联容器实际上是使用这些数据结构实现的。但这不仅仅是分裂头发。如果该标准确实提供了通用的树数据结构,那么它应该可以扩展以实现不同种类的树。但事实并非如此;它提供了一个带有接口的关联容器,该接口可以使用树来实现。
    猜你喜欢
    • 1970-01-01
    • 2016-05-03
    • 1970-01-01
    • 2011-05-28
    • 2019-11-19
    • 1970-01-01
    • 1970-01-01
    • 2010-12-03
    • 2012-02-28
    相关资源
    最近更新 更多