为什么std :: priority_queue中的插入和提取都采用对数时间?

时间:2016-10-07 15:53:10

标签: c++ sorting priority-queue

  

[std::priority_queue]是一个容器适配器,它提供最大(默认情况下)元素的恒定时间查找,但代价是对数插入和提取

为什么?我认为排序要么在插入或提取时发生。 例如,如果在插入时发生排序并且内部容器仍然排序,那么提取是否能够在恒定时间内完成?要删除的顶部元素是已知的,下一个较小的元素也是如此。

但是,std::priority_queue::pushstd::priority_queue::pop在复杂性描述中都提到了:

  

复杂性

     

对数的比较

为什么两者必须执行比较?对于保持分类的内部容器,提取应该很容易,反之亦然,在提取时进行分类,插入应该很容易。

我想我的假设是关于何时以及如何进行排序(或者是否有任何排序发生)是错误的。有人可以对此有所了解吗?

2 个答案:

答案 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位置:

init

然后将其与8交换(因为已排序的不变量已被破坏):

2nd step

然后最后用11交换它:

final step

在数组形式中,初始堆将存储为:

[11, 5, 8, 3, 4]

我们最终会:

[15, 5, 11, 3, 4, 8]

提取只是反向操作 - 冒泡而不是冒泡。如你所见,没有明确的“排序”。我们大多数时候都没有触及大部分元素。

std::priority_queue是一个容器适配器,但您提供的容器应该是一个随机访问容器,其O(1)复杂性可用于建立索引,push_back,{{ 1}},pop_backfront等等。因此容器的选择(除非你做错了)不会影响back操作的整体复杂性。

答案 1 :(得分:0)

弹出操作,删除顶部元素。有几种方法可以实现优先级队列,但在所有这些方法中,删除顶部是对数的。来自维基 - Priority queue