web-dev-qa-db-ja.com

STL priority_queueの効率

STL priority_queueで十分に機能するアプリケーション(C++)を持っています。 ドキュメント は言う:

Priority_queueはコンテナーアダプターです。つまり、基になるコンテナータイプの上に実装されます。デフォルトでは、基になるタイプはベクターですが、別のタイプを明示的に選択することもできます。

そして

プライオリティキューは標準的な概念であり、さまざまな方法で実装できます。この実装はヒープを使用します。

私は以前にassumedtop()O(1)であること、そしてPush()O(logn)になるであろう(最初にpriority_queueを選択した2つの理由)場所)-しかし、ドキュメントはこの仮定を確認も否定もしません。

より深く掘り下げて、Sequenceコンセプトのドキュメントはこう言っています:

単一要素の挿入と消去の複雑さはシーケンスに依存します。

priority_queueは、vector(デフォルト)をヒープとして使用します。

...要素へのランダムアクセス、最後の要素の一定時間の挿入と削除、および最初または中間の要素の線形時間の挿入と削除をサポートします。

デフォルトのpriority_queueを使用すると、top()O(1)であり、Push()O(n)であると推測しています。

質問1:これは正しいですか? (top()アクセスはO(1)であり、Push()O(n)?です)

質問2:setを使用した場合、O(logn)Push()効率を達成できますか?またはmultisetの代わりにvector)を使用してpriority_queueを実装しますか?これを行うとどのような影響がありますか?結果として他のどのような作業が影響を受けるでしょうか?

注:スペースではなく、時間の効率が心配です。

36
Chris Tonkinson

プライオリティキューアダプターは、標準ライブラリヒープアルゴリズムを使用してキューを作成し、キューにアクセスします。これは、ドキュメントで検索する必要があるアルゴリズムの複雑さです。

Top()操作は明らかにO(1)ですが、おそらく Josuttis に従って)呼び出した後にヒープをpop()したいのでO(2 * log(N))とPush()はO(log(N))-同じソースです。

そしてC++標準、25.6.3.1、Push_heapから:

複雑さ:最大でログ(最後-最初)の比較。

そしてpop_heap:

複雑さ:最大2 * log(最後-最初)の比較。

33
anon

top()-O(1)-これは要素@ frontを返すだけなので。

Push() -

  • ベクトルに挿入-0(1)償却
  • Push_into_heap-多くても、log(n)の比較。 O(logn)

    したがって、Push()の複雑さは-log(n)です。

7
aJ.

いいえ、これは正しくありません。 top()はO(1)で、Push()はO(log n)です。ドキュメントのメモ2を読んで、このアダプターがベクターの反復を許可していないことを確認してください。Neilは正しいpop()についてですが、これでもO(log n)時間で挿入と削除を行うヒープを操作できます。

5
Yuval F

基礎となるデータ構造がヒープの場合、top()は一定の時間になり、Push(編集:およびpop)は対数になります(あなたが言っているように)。ベクトルは、これらを次のように格納するために使用されます。

ヒープ:
1
2 3
8 12 11 9

VECTOR(保存に使用)

1 2 3 8 12 11 9

これは、i番目の子の要素が(2i)および(2i + 1)であると考えることができます。

データを順次格納するため、ベクターを使用します(ディスクリートよりもはるかに効率的でキャッシュに優しい)。

格納方法に関係なく、popが一定で、Pushが対数になるように、ヒープを常に実装する必要があります(特にSTD libを作成した神々によって)。

2
Bob Fincheimer

C++ STL priority_queueの基礎となるデータ構造は、ヒープデータ構造です(ヒープは、完全なバイナリツリーと完全なバイナリツリーに基づく非線形ADTであり、ベクター(または配列)コンテナーを介して実装されます。

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).
2
YADAV

Q1:標準は調べていませんが、AFAIKはvector(またはdeque btw)を使用しており、複雑さはO(1)の場合top()O(log n)およびPush()の場合はpop()。私はかつてstd::priority_queueを自分のヒープとO(1)Push()およびtop()およびO(log n)pop()で比較しましたが、確かにそうではありませんでした。 t O(n)と同じくらい遅い。

Q2:setpriority_queue(シーケンスではない)の基礎となるコンテナーとして使用できませんが、O(log n)Push()およびpop()。ただし、これはstd::priority_queueの実装よりもstd::vectorのパフォーマンスの方が優れているとは言えません。

1
jpalecek