std :: set和std :: priority_queue之间的区别

时间:2012-04-13 13:33:23

标签: c++ algorithm sorting priority-queue

由于std::priority_queuestd::set(以及std::multiset)都是存储元素的数据容器,并允许您以有序的方式访问它们,并且具有相同的插入复杂度{{1}使用一个优于另一个(或者,什么样的情况需要一个或另一个?)有什么好处?)

虽然我知道底层结构不同,但我对它们的实现差异并不感兴趣,因为我在比较它们的性能适用性各种用途。

注意:我知道集合中没有重复项。这就是为什么我也提到O(log n),因为它具有与std::multiset完全相同的行为,但可以在允许存储的数据作为相等元素进行比较的情况下使用。所以请不要评论单/多键问题。

4 个答案:

答案 0 :(得分:42)

优先级队列允许您按排序顺序访问一个元素 - 即,您可以获得优先级最高的项目,当您删除它时,您可以获得下一个最高优先级,依此类推。优先级队列也允许重复元素,因此它更像是多集而不是集。 [编辑:正如@Tadeusz Kopec指出的那样,构建堆也是堆中项目数量的线性,其中构建集合是O(N log N),除非它是从已经订购的序列构建的(在这种情况下)它也是线性的。]

一个集合允许您按排序顺序进行完全访问,因此您可以,例如,在集合中间的某处找到两个元素,然后按顺序从一个到另一个遍历。

答案 1 :(得分:28)

std::priority_queue允许执行以下操作:

  1. 插入元素O(log n)
  2. 获取最小元素O(1)
  3. 删除最小元素O(log n)
  4. 虽然std::set有更多可能性:

    1. 插入任何元素O(log n),常量大于std::priority_queue
    2. 查找任何元素O(log n)
    3. 查找元素> =而不是您要查找的元素O(log n)lower_bound
    4. 删除任何元素O(log n)
    5. 按排序顺序O(1)
    6. 移至上一个/下一个元素
    7. 获取最小元素O(1)
    8. 获取最大元素O(1)

答案 2 :(得分:23)

set / multiset通常由二叉树支持。 http://en.wikipedia.org/wiki/Binary_tree

priority_queue通常由堆支持。 http://en.wikipedia.org/wiki/Heap_(data_structure)

所以问题是你何时应该使用二叉树而不是堆?

两种结构都放在一棵树上,但是关于祖先之间关系的规则是不同的。

我们将父母的职位P称为左子女,左子女称为L,而右子则称为R.

在二叉树中L< P< R上。

在堆中P&lt; L和P < [R

所以二元树“横向排序”,堆排序“向上”。

因此,如果我们将其视为三角形而不是二叉树L,P,R是完全排序的,而在堆中L和R之间的关系是未知的(只有它们与P的关系)。

这具有以下效果:

  • 如果您有一个未排序的数组,并希望将其转换为二叉树,则需要O(nlogn)次。如果你想把它变成堆,它只需要O(n)时间,(因为它只是比较找到极端元素)

  • 如果您只需要极端元素(某些比较函数的最低或最高),则堆效率更高。堆只做必要的比较(懒惰)来确定极端元素。

  • 二叉树执行订购整个集合所需的比较,并始终对整个集合进行排序。

  • 堆具有最低元素的恒定时间查找(peek),二叉树具有最低元素的对数时间查找。

答案 3 :(得分:6)

Since both std::priority_queue and std::set (and std::multiset) are data containers that store elements and allow you to access them in an ordered fashion, and have same insertion complexity O(log n), what are the advantages of using one over the other (or, what kind of situations call for the one or the other?)?

Even though insert and erase operations for both containers have the same complexity O(log n), these operations for std::set are slower than for std::priority_queue. That's because std::set makes many memory allocations. Every element of std::set is stored at its own allocation. std::priority_queue (with underlying std::vector container by default) uses single allocation to store all elements. On other hand std::priority_queue uses many swap operations on its elements whereas std::set uses just pointers swapping. So if swapping is very slow operation for element type, using std::set may be more efficient. Moreover element may be non-swappable at all.

Memory overhead for std::set is much bigger also because it has to store many pointers between its nodes.