[
std::priority_queue
]是一个容器适配器,它提供最大(默认情况下)元素的恒定时间查找,但代价是对数插入和提取。
为什么?我认为排序要么在插入或提取时发生。 例如,如果在插入时发生排序并且内部容器仍然排序,那么提取是否能够在恒定时间内完成?要删除的顶部元素是已知的,下一个较小的元素也是如此。
但是,std::priority_queue::push
和std::priority_queue::pop
在复杂性描述中都提到了:
复杂性
对数的比较
为什么两者必须执行比较?对于保持分类的内部容器,提取应该很容易,反之亦然,在提取时进行分类,插入应该很容易。
我想我的假设是关于何时以及如何进行排序(或者是否有任何排序发生)是错误的。有人可以对此有所了解吗?
答案 0 :(得分:4)
例如,如果在插入时发生排序并且内部容器仍然排序,那么提取是否能够在恒定时间内完成?
提取可能会在固定时间内发生,但插入将变为O(n)
。您必须在列表中搜索该位置以插入新元素,然后移动所有其他元素。 O(1)
提取和O(n)
插入可能适用于某些用例,但不是priority_queue
试图解决的问题。
另一方面,如果排序发生在提取上,那么您将进行O(n lg n)
提取和O(1)
插入。对于某些用例来说,这也是有益的,但这不是priority_queue
所做的。
std::priority_queue
不是对元素进行排序,而是将其元素†存储在heap中,其构造具有O(lg n)
插入和提取功能。结构是树,插入/提取简单地保持树不变。对于某些问题(比如说,搜索),在我们需要插入和提取许多节点的情况下,两个操作都O(lg n)
远远优于O(n)/O(1)
。
作为示例,从Wikipedia窃取图像,将元素15插入堆中最初会将其放置在x
位置:
然后将其与8
交换(因为已排序的不变量已被破坏):
然后最后用11
交换它:
在数组形式中,初始堆将存储为:
[11, 5, 8, 3, 4]
我们最终会:
[15, 5, 11, 3, 4, 8]
提取只是反向操作 - 冒泡而不是冒泡。如你所见,没有明确的“排序”。我们大多数时候都没有触及大部分元素。
† std::priority_queue
是一个容器适配器,但您提供的容器应该是一个随机访问容器,其O(1)
复杂性可用于建立索引,push_back
,{{ 1}},pop_back
,front
等等。因此容器的选择(除非你做错了)不会影响back
操作的整体复杂性。
答案 1 :(得分:0)
弹出操作,删除顶部元素。有几种方法可以实现优先级队列,但在所有这些方法中,删除顶部是对数的。来自维基 - Priority queue。