使用' std::greater '通过' priority_queue '创建最小堆的原因
The reason of using `std::greater` for creating min heap via `priority_queue`
我想知道为什么要使用priority_queue
创建最小堆,应该使用std::greater
?
std::priority_queue<T, std::vector<T>, std::greater<T> > min_heap;
对我来说,因为最小的值总是位于堆的顶部,所以使用的类应该是std::less
更新:另一方面,由于priority_queue
(最大堆)的默认行为是在顶部保存最大的值,因此在我看来,std::greater
应该用于最大堆创建,而不是用于最小堆创建
逻辑参数如下
-
std::priority_queue
是容器适配器;基于基本的内存考虑,对于序列容器(如std::vector
),后面是修改的首选位置(pop_back()
和push_back()
)。 -
priority_queue
原语基于std::make_heap
(构造函数),std::pop_heap
+container::pop_back
(priority_queue::pop
)和container::push_back
+std::push_heap
(priority_queue::push
) -
pop_heap
将获取底层存储的前面,并将其放在后面,然后恢复堆不变量。push_heap
则相反。 - 在
max_heap
上执行sort_heap
(最初将max放在前面)将重复地将前面弹出到后面,并根据less
(这是默认的比较运算符)对范围进行排序 - 因此,
max_heap
的首选实现是将最大元素w.r.t.less
放在前面,通过priority_queue::top
(底层container::front
)访问。 - 仍然可以争论
priority_queue
与std::less
比较器代表max_heap
是否直观。它可以通过反转比较器的参数来定义为min_heap
(但请参阅@ tc的评论)。对于c++ 98的绑定器,这是相当冗长的),在调用各种堆函数中无处不在。一个(对我来说)反直觉的结果是top()
不会给top优先级的元素
c++堆函数make_heap
、push_heap
和pop_heap
在最大堆上操作,这意味着当使用默认比较器时,顶部元素是最大值。因此,要创建最小堆,您需要使用greater<T>
而不是less<T>
。
我怀疑使用最大堆而不是最小堆是因为使用less
操作更容易实现。在c++中,less
具有作为所有STL算法的"默认"比较器的特权;如果您只打算实现一个比较操作(而不是==
),则应该是<
。这就导致了priority_queue<T, C<T>, less<T>>
表示最大队列,而priority_queue<T, C<T>, greater<T>>
表示最小队列。
同样,某些算法,如nth_element
,需要一个max-heap。
这是一个将优先级队列转换为排序序列的过程。
我们如何做到这一点?
假设我们现在有一个最大堆,我们执行下面的过程:
HEAP-SORT(A)
for i = A.heap_size downto 2
exchange A[1] with A[A.heap_size]
A.heapsize -= 1
max_heapify(A)
当我们完成这个过程,我们得到一个递增顺序的序列。
我们注意到,每次比较两个元素时,总是把较大的元素放回数组中,这意味着较小的元素在较大的元素的左边。
这与将less操作符传递给std::sort算法以获得递增顺序序列的想法相匹配。
priority_queue
是一种数据结构,它以具有最高优先级的元素始终位于队列顶部的方式存储元素。缺省情况下,元素的优先级由其值决定。但是,可以使用函子来改变确定元素优先级的方式。
函子是一个小的函数对象,可以用来执行特定的任务。在本例中,greater<int>
函子用于比较两个整数,如果第一个整数大于第二个整数,则返回true。
当对priority_queue
使用greater<int>
函子时,具有最低值的元素将被认为具有最高优先级。这是因为当将具有最低值的元素与任何其他元素进行比较时,greater<int>
函子总是返回true。
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 使用std::multimap迭代器创建std::list
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- 使用CMake创建QML插件
- 如何在c++中为模板函数实例创建快捷方式
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- OpenCV EqualizeHist()从彩色图像创建黑白图像
- 试图在visual studio上用C++创建一个桌面应用程序
- std::threads可以从Windows DLL中的全局变量创建/销毁吗?
- 如何在C++20中创建模板别名的推导指南
- 如何为模板化对象创建模板向量?VS正在投掷C3203
- 如何创建一个空的全局类并在启动时实例化它
- 无法创建抽象类的实例
- 链接到自行创建的dll失败
- 为什么我不能在不创建字符串变量的情况下使用函数的字符串输出
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 如何在C++类内存结构中创建"spacer"?
- 终端不会为C++文件创建.exe文件吗
- 在createdialog创建的窗口中捕获用于编辑控件的OnMouseMove消息