如何从std :: heap弹出min元素?

gsa*_*ras 2 c++ heap stl vector c++11

我有一个std::vector,我用std::heap它.

我希望在while循环中,每次循环开始时弹出最小值.在循环体中,另一个元素将插入堆中.循环在多次运行后停止.

我想到的是使用std::sort_heap然后擦除第一个元素.但是,这似乎不是一个好主意.你看,在我的代码的这一部分,速度是真正的本质.

我不认为这是一个好主意,因为我必须std::sort_heap在每次运行时调用,因为一个元素将要插入,从而std::vector再次成为一个堆,这意味着我必须再次对它进行排序,以便最小元素放在前面.

而且,从开始删除,vector.erase()比删除最后一个元素慢,对吗?如果我删除了第一个元素,那么所有其他元素都必须向左移动一个位置.如果我删除最后一个元素,我只需支付删除费用.

这引出了我的想法,按照我的方式对向量进行排序,以便最小元素将结束,从而仅删除最后一个元素.但是,这仍然需要在每次循环运行时进行排序,对吗?

哪种方法可以解决这个问题?

How*_*ant 7

一个std::heap排序与std::less可以很容易地提取最大的元素,而不是最小的.但是,如果使用std::greater,则可以有效地提取min元素.

std::pop_heap,using std::greater,将最小元素放在序列的后面,并将堆的大小减小一.然后,您可以使用新元素读取back()和写入back().

std::push_heap,using std::greater,将元素插入序列的后面,将堆的大小增加一.

在代码中:

#include <algorithm>
#include <vector>
#include <iostream>

int
main()
{
    std::vector<int> v{5, 4, 6, 9, 0, 1, 2, 3};
    std::make_heap(v.begin(), v.end(), std::greater<int>{});
    int i;
    while (std::cin >> i)
    {
        // pop minimum, and place at back()
        std::pop_heap(v.begin(), v.end(), std::greater<int>{});
        // write min out
        std::cout << "min = " << v.back() << '\n';
        // push a new element into the heap
        v.back() = i;
        std::push_heap(v.begin(), v.end(), std::greater<int>{});
    }
}
Run Code Online (Sandbox Code Playgroud)

这一切都非常有效,vector因为提取和插入实际上是在后面vector.因为我们正在使用greater,我们实际上每次都提取最小元素(这有点不直观).

如果需要,可以将上述逻辑封装在一个std::priority_queue<T, std::vector<T>, std::greater<T>>简单地适应vector和暴露push,pop以及top成员函数而不是vector's push_back,pop_backback.这个适配器只需调用make_heap,push_heappop_heap在适当的位置.

更新

TemplateRex正确指出在C++ 14中greater<>可以代替使用greater<int>.例如:

std::make_heap(v.begin(), v.end(), std::greater<>{});
Run Code Online (Sandbox Code Playgroud)

这创建了一个异构的函子,可以接受任何两个参数,而不仅仅是int:

template <>
struct greater<void>
{
    template <class T1, class T2>
    auto operator()(T1&& t, T2&& u) const
        { return std::forward<T1>(t) > std::forward<T2>(u); }
    typedef void is_transparent;
};
Run Code Online (Sandbox Code Playgroud)

使用此新功能,只需更改vector更改类型(以及类型i),示例的其余部分将自动适应类型的更改.

  • @mattnewport [本工作文件](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3421.htm)或[本问答](http://stackoverflow.com/问题/ 20317413 /什么,是透明的,比较器) (2认同)