如何从 std::heap 弹出最小元素
How to pop min element from std::heap?
我有一个std::vector
,我在上面用std::heap
。
我想在 while 循环中,每次循环开始时弹出最小值。在循环的主体中,另一个元素将插入到堆中。循环在多次运行后停止。
我想到的是使用std::sort_heap
然后擦除第一个元素。但是,这似乎不是一个好主意。你看,速度在我的代码的这一部分是真正重要的。
我认为这不是一个好主意,因为我必须在每次运行时调用std::sort_heap
,因为将要插入一个元素,从而使std::vector
再次堆,这意味着我必须再次对其进行排序,以便将最小元素放在前面。
此外,从头开始擦除vector.erase()
比擦除最后一个元素慢,对吧?如果我删除第一个元素,那么所有其他元素都必须向左移动一个位置。如果我删除最后一个元素,我只需支付删除费用。
这让我想到了这个想法,按照我的方式对向量进行排序,以便最小元素将走到尽头,从而只支付最后一个元素的删除。但是,这仍然需要在循环的每次运行时进行排序,对吧?
解决这个问题的最佳方法是什么?
使用std::less
排序的std::heap
可以轻松提取最大的元素,而不是最小的元素。 但是,如果使用 std::greater
,则可以有效地提取 min 元素。
std::pop_heap
,使用 std::greater
,会将最小元素放在序列的后面,并将堆的大小减少 1。 然后,您可以读取back()
并使用新元素写入back()
。
std::push_heap
,使用 std::greater
,将元素插入序列的后面,将堆的大小增加 1。
在代码中:
#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>{});
}
}
这一切都在使用vector
非常有效,因为提取和插入实际上位于vector
的后面。 而且因为我们使用 greater
,我们实际上每次都提取最小元素(这有点不直观(。
如果需要,上述逻辑可以封装在一个std::priority_queue<T, std::vector<T>, std::greater<T>>
中,该简单地适应vector
并公开push
、pop
和top
成员函数,而不是vector
的push_back
、pop_back
和back
。 这个适配器将简单地调用make_heap
,push_heap
并在适当的位置pop_heap
。
更新
模板Rex正确地指出,在C++14中,greater<>
可以用来代替greater<int>
。 例如:
std::make_heap(v.begin(), v.end(), std::greater<>{});
这将创建一个异构函子,它可以接受任何两个参数,而不仅仅是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;
};
有了这个新功能,只需更改vector
即可更改类型(以及i
的类型(,示例的其余部分将自动适应类型的更改。
我认为你只是想要一个std::priority_queue<T>
.它具有O(log n)
推送和弹出的复杂性。
看看pop_heap和push_heap。正如 sharth 所建议的那样,您还可以使用 priority_queue 容器适配器,该适配器通过方便的优先级队列接口包装堆功能。
std::sort_heap
不会创建堆 - 相反,它将堆作为其输入,并生成完全排序的元素作为其输出。
您可以按照@Sharth的建议使用priority_queue
。如果您希望直接使用堆,则可以使用 push_heap
和 pop_heap
分别删除最小的项目并插入新项目。
请注意,与大多数算法不同,push_heap
和 pop_heap
只是重新排列范围内的项目。 即,pop_heap
移动堆中最小(或最大,取决于您的比较函数(项目,并将其移动到范围的末尾,并将前面的元素重新排列到有效的堆中。
同样,push_heap
在内存的一个部分中获取一个堆,然后在内存中的下一个位置获取一个项目,并将该元素添加到堆中,因此整个元素再次形成一个有效的堆。
- Mongodb c++驱动程序:如何查询元素的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 使用strcpy将char数组的元素复制到另一个数组
- 使用不带参数的函数访问结构元素
- 给定n个元素的m个集合.在C++中找到出现在最大集合数中的元素
- C++如何通过用户输入删除列表元素
- lower_bound()返回最后一个元素
- 基于多个条件处理地图中的所有元素
- 调整大小后指向元素值的指针unordered_map有效?
- 使用std::transform将一个范围的元素添加到另一个范围中
- 使用函数"remove"删除重复元素
- 具有最大子序列大小的序列,每个元素都相同
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- 如何将元素添加到数组的线程安全函数?
- 有没有办法将谓词中的元素偏移量传递给 std 算法?
- 我想访问std::unique_ptr中的一个特定元素
- 如何通过 getter 函数删除矢量的元素?
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- 从控制台中删除最后打印的元素
- 如何从 std::heap 弹出最小元素