我正在阅读priority_queue的文档(基本上是make_heap的包装器),它发现你可以使用比较函数对它进行自定义。
从文档(http://en.cppreference.com/w/cpp/container/priority_queue):
可以提供用户提供的比较来更改排序,例如 使用std :: greater会导致最小元素显示为 顶部()。
在维基百科和其他CS文本中,堆定义如下:
在计算机科学中,堆是一种专门的基于树的数据结构 满足堆属性:如果A是B的父节点,那么 节点A的密钥(值)相对于节点B的密钥排序 在堆中应用相同的顺序。堆可以 进一步分类为“最大堆”或“最小堆”。 最多 堆,父节点的键总是大于或等于 子节点和最高键的位于根节点中。
但是在std :: priority_queue实现中,提供std :: greater会导致创建MinHeap(顶部的最小元素)。我会期望最大堆,因为定义了堆排序(在我读过的所有文献中)if(parent comparator children)是真的。
我发现这种API设计令人困惑。
有没有理由这样定义?
答案 0 :(得分:3)
我发现它也令人困惑,但从一个不同的角度来看。假设您要按升序对序列进行排序。有几种方法可以做到:
std::vector
或std::deque
并使用 std::sort()
运行std::less
。std::list
并使用 std::list::sort()
运行std::less
。std::set
配置的std::less
,最后会自动排序。std::vector
或std::deque
中,然后使用 std::make_heap()
运行std::pop_heap()
后跟std::less
- 。< / LI>
std::priority_queue
(!!!)将您的数据推送到std::greater
。正如我们所看到的,std::priority_queue
从这种观点来看是一个明确的异常值。
实际上,std::priority_queue
在这方面的混淆行为背后的原因隐藏在第(4)项中,因为这是std::priority_queue
下面的内容。 (4)也违背了我的直觉(尽管程度较小),因为在中间状态(虽然并非所有std::pop_heap
都已执行),序列的已排序部分位于其上限,而不是下部范围。
但它也解释了为什么为标准库选择了最大堆 - std::pop_heap
将弹出元素放在该位置,从那里可以在恒定时间内删除它,无论使用何种容器类型。
答案 1 :(得分:2)
这可以解决问题 - 提供std::greater
实际上会产生最小堆。
原因如下:从堆的角度来看,比较器在堆上定义小于的关系,即使它实际上正在做其他事情。当std::priority_queue
需要插入元素时,它会调用比较器并为其提供两个元素。如果比较器返回true
,则认为第一个元素小于第二个元素,并将第二个元素放在第一个元素中(因为std::priority_queue
是 max heap 实现)。结果,你最终得到了最小堆。