【问题标题】:Efficiency of the STL priority_queueSTL priority_queue 的效率
【发布时间】:2011-02-27 19:16:45
【问题描述】:

我有一个应用程序 (C++),我认为 STL priority_queue 会很好地为它服务。 The documentation 说:

Priority_queue 是一个容器适配器,这意味着它是在一些底层容器类型之上实现的。默认情况下,底层类型是矢量,但可以显式选择不同的类型。

优先队列是一个标准概念,可以通过多种不同的方式实现;此实现使用堆。

我之前假设top()O(1),而push() 将是O(logn)(我首先选择priority_queue 的两个原因)-但文档既不确认也不否认这一假设。

深入挖掘,序列概念的文档说:

单元素插入和擦除的复杂性取决于序列。

priority_queue 使用vector(默认)作为堆,其中:

...支持对元素的随机访问,在结尾处恒定时间插入和移除元素,在开头或中间支持线性时间插入和移除元素。

我推断,使用默认的priority_queuetop()O(1)push()O(n)

问题 1:这是正确的吗? (top() 访问权限是O(1)push()O(n)?)

问题 2:如果我使用 set(或 multiset)而不是 vector 来实现priority_queue?这样做会有什么后果?其他操作会因此受到影响?

注:我担心的是时间效率,而不是空间。

【问题讨论】:

    标签: c++ data-structures stl performance priority-queue


    【解决方案1】:

    优先级队列适配器使用标准库堆算法来构建和访问队列 - 您应该在文档中查找这些算法的复杂性。

    top() 操作显然是 O(1) 但大概你想在调用它之后 pop() 堆(根据Josuttis)是 O(2*log(N)) 并且 push() 是O(log(N)) - 相同的来源。

    并且来自 C++ 标准,25.6.3.1,push_heap:

    复杂性:最多日志(最后 - 第一个)比较。

    和pop_heap:

    复杂性:最多 2 * log(last - first) 比较。

    【讨论】:

      【解决方案2】:

      top() - O(1) - 因为它只是返回元素@front。

      push() -

      • 插入向量 - 0(1) 摊销
      • push_into_heap - 最多 log(n) 个比较。 O(logn)

        所以 push() 的复杂度是—— 日志(n)

      【讨论】:

        【解决方案3】:

        没有。这是不正确的。 top() 是 O(1),而 push() 是 O(log n)。阅读文档中的注释 2 以了解此适配器不允许遍历向量。 Neil 对 pop() 的看法是正确的,但这仍然允许在 O(log n) 时间内使用堆进行插入和删除。

        【讨论】:

          【解决方案4】:

          如果底层数据结构是堆,top() 将是常数时间,而 push(编辑:和 pop)将是对数的(就像你说的那样)。向量只是用来存储这些东西:

          堆:
          1
          2         3
          8 12 11 9

          矢量(用于存储)

          1 2 3 8 12 11 9

          你可以把它想象成位置 i 的子元素是 (2i) 和 (2i+1)

          他们使用向量是因为它顺序存储数据(这比离散的更高效且缓存友好)

          无论它是如何存储的,都应该始终实现堆(尤其是由制作 STD 库的神),以便 pop 是恒定的,push 是对数的

          【讨论】:

          • 这样不行:pop() 重新排序向量以保持堆属性,因此是 O(log n)。
          • 其实恰恰相反——神一样的堆有 push O(1),但是 pop O(log n)
          • 推送怎么可能是 O(1)。如果新项目必须成为新的顶部或新的底部,但如果它需要位于中间的某个位置,则需要调用 update heap 一个 O(lg n) 函数。
          • peek() 是 O(1),但 pop() 是 O(log(N)),push() 也是如此。
          【解决方案5】:

          C++ STL priority_queue底层数据结构是Heap数据结构(Heap是一种基于完全二叉树的非线性ADT,完全二叉树是通过vector(或Array)容器实现的。

          ex  Input data : 5 9 3 10 12 4.
          
          Heap (Considering Min heap) would be :
          
                             [3]
                       [9]             [4]
                   [10]    [12]     [5]
          
          
             NOW , we store this min heap in to vector,             
                [3][9][4][10][12][5].
                Using formula ,
                Parent : ceiling of n-1/2
                Left Child : 2n+1
                Right Child : 2n+2 .
            Hence ,
              Time Complexity for 
                       Top = O(1) , get element from root node.
                       POP()= O(logn) , During deletion of root node ,there  is      chance to violation of  heap order . hence restructure of heap order takes at most O(logn) time (an element might move down to height of tree).
                      PUSH()= O(logn) , During insertion also , there might chance to violation of  heap order . hence restructure of heap order takes at most O(logn) time (an element might move up to root from leaf node).
          

          【讨论】:

            【解决方案6】:

            Q1:我没有查看标准,但 AFAIK,使用 vector(或 deque 顺便说一句),复杂性将是 O(1) 用于 top()O(log n) 用于 push() 和 @ 987654327@。我曾经将std::priority_queue 与我自己的堆与O(1) push()top()O(log n) pop() 进行比较,它肯定没有O(n) 慢。

            Q2:set 不能用作 priority_queue(不是序列)的底层容器,但可以使用 set 来实现具有 O(log n) push()pop() 的优先级队列。但是,这可能不会优于 std::priority_queue 而不是 std::vector 实现。

            【讨论】:

            • 与您的实施相比,STL PQ 的速度有多慢?
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-08-03
            • 2021-09-26
            • 1970-01-01
            • 2011-01-27
            • 1970-01-01
            相关资源
            最近更新 更多