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

由于std::priority_queuestd::set (和std::multiset )都是数据容器,它们存储元素并允许以有序方式访问它们,并具有相同的插入复杂度O(log n) (或者,什么样的情况需要这个或那个?)?

虽然我知道潜在的结构是不同的,但我并不那么感兴趣,因为我在比较它们的性能和各种用途的适用性

注:我知道一套中没有重复。 这就是为什么我还提到了std::multiset因为它具有与std::set完全相同的行为,但是可以在允许存储的数据作为相等元素进行比较的情况下使用。 所以,请不要评论单个/多个密钥的问题。

一个优先级队列允许你按照sorting顺序访问一个元素 – 也就是说,你可以得到最高优先级的项目,当你删除它时,你可以获得下一个最高优先级,依此类推。 优先级队列也允许重复的元素,所以它更像是一个多集而不是集。 Kopec指出,构build一个堆对于堆中的项目数量也是线性的,其中构build集合的地方是O(NlogN),除非它是从一个已经sorting的序列构build的(在这种情况下它也是线性的)。]

一个集合允许你按照sorting顺序完全访问,例如,你可以在集合的中间find两个元素,然后按照从一个到另一个的顺序遍历。

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 <L和P <R

所以二叉树sorting“侧面”和堆sorting“向上”。

所以如果我们把它看作一个三angular形而不是二叉树L,P,R是完全sorting的,而在堆中L和R之间的关系是未知的(只有它们与P的关系)。

这具有以下效果:

  • 如果你有一个没有sorting的数组,并且想把它变成一个二叉树,它需要O(nlogn)时间。 如果你想把它变成一堆,它只需要O(n)时间,(因为它只是比较find极端的元素)

  • 如果你只需要极端元素(比较函数最低或最高),堆更有效率。 堆只做比较(懒惰),以确定极端的因素。

  • 二叉树执行必要的比较,以便对整个集合进行sorting,并保持整个集合一直sorting。

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

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

  1. 插入一个元素O(log n)
  2. 获得最小的元素O(1)
  3. 删除最小的元素O(log n)

std::set有更多的可能性:

  1. 插入任何元素O(log n) ,常量大于std::priority_queue
  2. find任何元素O(log n)
  3. find一个元素,> =比你正在寻找的O(log n)lower_bound
  4. 删除任何元素O(log n)
  5. 按sorting顺序移至上一个/下一个元素O(1)
  6. 获得最小的元素O(1)
  7. 获得最大的元素O(1)

由于std::priority_queuestd::set (和std::multiset )都是数据容器,它们存储元素并允许以有序方式访问它们,并具有相同的插入复杂度O(log n) (或者,什么样的情况需要这个或那个?)?

尽pipe两个容器的插入擦除操作都具有相同的复杂度O(log n) ,但这些std :: set的操作比std :: priority_queue慢。 这是因为std :: set使得许多内存分配。 std :: set的每个元素都存储在自己的分配中。 std :: priority_queue (默认使用std :: vector容器)使用单个分配来存储所有元素。 另一方面, std :: priority_queue在其元素上使用了许多交换操作,而std :: set只是使用指针交换。 所以如果交换元素types的操作非常慢,使用std :: set可能更有效率。 而且元素可能是不可交换的。

std :: set的内存开销也大得多,因为它必须在其节点之间存储许多指针。