make_heap有什么意义?

rlb*_*ond 46 c++ stl language-design

有人可以告诉我STL堆函数模板的重点std::make_heap吗?为什么有人会使用它们?有实际用途吗?

Jam*_*son 43

算法和数据结构中的类将很好地回答您的直接问题.堆在计算机科学中的算法中被广泛使用.要引用下面链接的make_heap函数,"堆是一个树,其中每个节点链接到不大于其自身值的值." 虽然堆有很多应用程序,但是当您想要有效地跟踪N个值的排序列表时,我最常使用的是搜索问题.

当我第一次遇到STL堆函数时,我遇到了类似的困惑.我的问题虽然有点不同.我想知道"为什么STL堆不在与std :: vector相同的数据结构类中?" 我认为它应该像这样工作:

std::heap< int > my_heap;
my_heap.heap_insert( 7 );
my_heap.heap_insert( 3 );
Run Code Online (Sandbox Code Playgroud)

STL堆函数背后的想法是,它们允许您从几个不同的底层STL容器中创建堆数据结构,包括std :: vector.如果您想要传递容器以在程序中的其他位置使用,这可能非常有用.它也有点好看,因为如果你选择使用除std :: vector之外的其他东西,你可以选择堆的底层容器.您真正需要的是以下内容:

template <class RandomAccessIterator>
  void make_heap ( RandomAccessIterator first, RandomAccessIterator last );
Run Code Online (Sandbox Code Playgroud)

这意味着您可以将许多不同的容器放入堆中.比较器在方法签名中也是可选的,您可以阅读有关make_heap函数的STL页面中可以尝试的不同内容的更多信息.

链接:

  • 实际上有一个堆模板类`std :: priority_queue`,所以你不需要使用`std :: make_heap`来构建堆. (8认同)

aka*_*ppa 21

如果要从列表中创建优先级队列,那么可以使用make_heap:

在内部,堆是树,其中每个节点链接到不大于其自身值的值.在由make_heap生成的堆中,元素在树中的特定位置而不是由消耗内存的链接确定由其在序列中的绝对位置确定,其中*first始终是堆中的最高值.

堆允许通过使用函数push_heap和pop_heap在对数时间内添加或删除元素,这些函数保留其堆属性.

  • 堆只是元素的顺序排列,它允许您满足上述边界。也就是说,“make_heap”只是将向量中的数据打乱,仅此而已。对元素进行排序也可能是一种选择,但插入和删除需要*线性*时间而不是对数时间(例如,在添加时需要为新元素腾出空间,这需要线性时间)。 (2认同)

new*_*cct 8

您应该std::make_heap()与向量或数组一起使用std::push_heap()std::pop_heap()维护二进制堆; 后两个函数保持堆不变.您还可以使用它std::heap_sort()来对这样的堆进行排序.虽然您可以使用std::priority_queue优先级队列,但它不会让您了解它的内部,这可能是您想要做的.此外,std::make_heap()std::heap_sort()共同使用C做堆排序++的一个非常简单的方法.


Jør*_*ogh 8

std::make_heap应该几乎不会在实践中使用.虽然堆对优先级队列很有用,但这并不能解释为什么要手动维护结构.std::priority_queue如果你需要的只是一个优先级队列,它有一个更有用的接口.

如果您make_heap直接使用它的兄弟姐妹,则必须确保每次更改底层容器时都使用它们.我看过他们使用了两三次,而且每次使用都不正确.

我自己一直只使用堆操作,因为我需要使用一个向量作为优先级队列一段时间然后对它进行排序.你很可能永远不需要std::make_heap.

如果您需要具有更改元素功能的优先级队列,则可以使用std::set.您可以使用*s.begin()*s.rbegin()分别获取最小或最大元素,并通过删除旧值并插入新值来更新元素.

  • 正如其他人在两年前指出的那样*在提出这个问题时,这些功能都有好处.最值得注意的是,您可以根据需要快速从未分类数据转到分类数据,而无需维护两组独立的数据.如果你需要的只是一个堆,那么`std :: priority_queue`是很有用的,但是如果你的需求比这更复杂,那么自己做那些咕噜咕噜的工作[堆函数非常容易]可能是非常有益的. (3认同)
  • @Dennis Zickefoose:据我所知,我是唯一一个在将数据用作优先级队列后对数据进行排序的情况.这就是为什么我写*几乎*永远不会.简单地说`make_heap`用于创建堆不是一个有用的答案,特别是因为如果你*只需要一个堆,你很少想要使用它. (3认同)
  • @JørgenFogh std::priority_queue 没有办法将已知集合转换为队列。如果一次性完成所有队列,则创建队列的时间复杂度为 O(n),但如果一次完成一个元素,则创建队列的时间复杂度为 O(n log n)。如果这很重要,则不能使用 std::priority_queue (2认同)

Nik*_*chi 5

构造[二进制]堆基本上有两种方法:创建一个空堆并一次一个地插入每个元素,或者获取一系列值并将它们堆积起来.

堆上的每个推送操作都需要O(logn)时间,因此如果要将N个项目推送到堆上,则需要O(NlogN)时间.但是,从值数组构建二进制堆只需要O(N)时间.

因此,将每个元素插入到数组(或支持随机访问迭代器的其他容器)中然后在数组上调用make_heap()比在插入时维护堆结构更有意义.