実際にフィボナッチヒープを効率的に実装した人はいますか?


151

あなたの誰かがフィボナッチヒープを実装したことがありますか?私は数年前にそうしましたが、配列ベースのBinHeapsを使用するよりも数桁遅くなりました。

当時、私はそれが研究が主張するほど必ずしも良いとは限らないということについての貴重な教訓だと思っていました。ただし、多くの研究論文では、フィボナッチヒープの使用に基づくアルゴリズムの実行時間を主張しています。

効率的な実装を実現できたことがありますか?または、フィボナッチヒープの方が効率的であるほど大きなデータセットを使用しましたか?もしそうなら、いくつかの詳細をいただければ幸いです。


25
これらのアルゴリズムの男は常に大きな定数の背後に巨大な定数を隠していることを学びましたか?:)実際には、ほとんどの場合、「n」のものは「n0」に近づくことさえないようです!
Mehrdad Afshari、

私は知っています-今。「アルゴリズム入門」のコピーを初めて入手したときに実装しました。また、彼のスプレイツリーは実際には非常に優れているため、役に立たないデータ構造を発明する人のためにTarjanを選びませんでした。
mdm

mdm:もちろん、それは役に立たないわけではありませんが、小さなデータセットでのクイックソートに勝る挿入ソートと同じように、定数が小さいため、バイナリヒープはよりうまく機能する可能性があります。
Mehrdad Afshari、

1
実際、ヒープを必要とするプログラムは、VLSIチップでルーティングするためのスタイナーツリーを見つけることでした。そのため、データセットは正確には小さくありませんでした。しかし、今日(並べ替えのような単純なものを除いて)、データセットで「壊れる」まで、常により単純なアルゴリズムを使用していました。
mdm

1
これに対する私の答えは、実際には「はい」です。(まあ、私の論文の共同執筆者はそうしました。)私は現在コードを持っていないので、実際に応答する前に詳細情報を入手します。ただし、グラフを見ると、Fヒープはbヒープよりも比較が少ないことがわかります。比較が安いところを使っていましたか?
A.レックス

回答:


136

ブーストC ++ライブラリは、中フィボナッチヒープの実装が含まれますboost/pending/fibonacci_heap.hpp。このファイルは明らかpending/に何年も前から存在しており、私の予測では決して受け入れられません。また、その実装にはバグがあり、私の知り合いであり、万能のクールな男であるアーロンウィンザーによって修正されました。残念ながら、オンラインで見つけたそのファイルのバージョンのほとんど(Ubuntuのlibboost-devパッケージにあるもの)にはまだバグがありました。Subversionリポジトリからクリーンバージョンを取得する必要がありました。

バージョン1.49 以降、Boost C ++ライブラリはフィボナッチヒープを含む多くの新しいヒープ構造を追加しました。

私はコンパイルすることができたdijkstra_heap_performance.cppを修正版に対してdijkstra_shortest_paths.hppフィボナッチヒープとバイナリヒープを比較します。(の行でtypedef relaxed_heap<Vertex, IndirectCmp, IndexMap> MutableQueue、に変更relaxedfibonacciます。)最初に最適化を使用してコンパイルするのを忘れました。この場合、フィボナッチヒープとバイナリヒープはほぼ同じように動作し、フィボナッチヒープは通常、わずかな量でパフォーマンスが向上します。非常に強力な最適化でコンパイルした後、バイナリヒープが大幅に向上しました。私のテストでは、フィボナッチヒープは、グラフが信じられないほど大きくて密度が高い場合にのみ、バイナリヒープよりも性能が優れていました。

Generating graph...10000 vertices, 20000000 edges.
Running Dijkstra's with binary heap...1.46 seconds.
Running Dijkstra's with Fibonacci heap...1.31 seconds.
Speedup = 1.1145.

私が理解している限り、これはフィボナッチヒープとバイナリヒープの基本的な違いに触れています。2つのデータ構造の唯一の実際の理論的な違いは、フィボナッチヒープが(償却された)一定の時間で減少キーをサポートすることです。一方、バイナリヒープは、配列としての実装から大きなパフォーマンスを得ます。明示的なポインター構造を使用すると、フィボナッチヒープが大きなパフォーマンスヒットを被ります。

したがって、実際にフィボナッチヒープの恩恵を受けるには、recrease_key が非常に頻繁に使用されるアプリケーションで使用する必要があります。ダイクストラに関しては、これは基礎となるグラフが密であることを意味します。一部のアプリケーションは、本質的に減少する可能性があります。Nagomochi-Ibarakiミニマムカットアルゴリズムを試してみたかったのは、明らかにそれは多くの減少キーを生成するからです。

警告:何か間違ったことをした可能性があります。これらの結果を自分で再現してみてください。

理論上の注意:減少したキーでのフィボナッチヒープのパフォーマンスの向上は、ダイクストラのランタイムなどの理論的なアプリケーションにとって重要です。フィボナッチヒープは、挿入時およびマージ時にバイナリヒープよりも優れています(フィボナッチヒープの場合はどちらも一定時間で償却されます)。挿入はダイクストラの実行時間に影響を与えないため、本質的に無関係です。バイナリヒープを変更して、一定の時間内に挿入することも簡単です。一定時間のマージは素晴らしいですが、このアプリケーションには関係ありません。

個人的なメモ:私の友人と私は、フィボナッチヒープの(理論上の)実行時間を複雑にすることなく複製しようとした新しい優先度キューを説明する論文をかつて書いた。論文は公開されませんでしたが、私の共著者は、バイナリヒープ、フィボナッチヒープ、およびデータ構造を比較するための独自の優先キューを実装しました。実験結果のグラフは、フィボナッチヒープが比較全体の観点からわずかにパフォーマンスが向上したバイナリヒープであることを示しており、比較コストがオーバーヘッドを超える状況ではフィボナッチヒープのパフォーマンスが向上することを示唆しています。残念ながら、私は利用可能なコードを持っていません。おそらくあなたの状況での比較は安いので、これらのコメントは関連がありますが、直接は当てはまりません。

ちなみに、フィボナッチヒープのランタイムを独自のデータ構造と一致させることを強くお勧めします。私はフィボナッチ山を自分で単純に再発明したことがわかりました。フィボナッチヒープの複雑さはすべてランダムなアイデアだと思っていたが、その後、それらはすべて自然でかなり強制されていることに気づきました。


ありがとう!この質問はずっと頭に浮かんできました。シュタイナーツリーを試す前に、フィボナッチヒープを使用してダイクストラを実際に実装しました。しかし、私のグラフはあなたの例よりもはるかに密度が低いようです。数百万のノードがありましたが、平均の程度はわずか5〜6です。
mdm

Fib Heapのパフォーマンスは、一連の操作によって予測可能です。私は、Fib Heap(vs. Bin Heap)でより速く終了するHeap-heavyアルゴリズムを作成しました。トリックは、作業をバッチ処理することでした。操作の頻度に関係なく、違いは次のとおりです。DecreaseKey-ExtractMin-DecreaseKey-ExtractMinとDecreaseKey-DecreaseKey-ExtractMin-ExtractMin(続き)
Gaminic

2番目のExtractMinはほぼ無料なので、後者は約2倍の速度になります。私たちのアルゴリズムは、多くが破棄されるMin要素のバッチを抽出します。Binヒープでは無駄ですが、Fibヒープでは無駄になります。悲しいことに、これは、ヒープベースのアルゴリズムについて話すときに人々が提供する時間の複雑さに明確に反映されていません。償却境界を使用すると、全体の複雑さは単純に#操作*操作の複雑さではありません。
Gaminic 2014

1
ヒープとリラックスしたヒープのペアリングを試みる可能性はありますか?
Thomas Ahle

1
結果が非常に近いように見える理由がわかりません。STLのpriority_queueと自己実装のフィボナッチヒープを使用しましたが、テストではバイナリヒープが大幅に遅れていました。
ニコラスピピトーネ

33

Knuthは、彼の著書であるStanford Graphbaseについて、1993年に最小スパンツリーのフィボナッチヒープとバイナリヒープを比較しました。彼は、テストしているグラフのサイズ、異なる密度で128の頂点で、フィボナッチがバイナリヒープよりも30〜60%遅いことを発見しました。

ソースコードは、セクションMILES_SPANに(C、数学およびTeXの間のクロスであるか、またはむしろCWEB)Cです。


1

免責事項

結果は非常によく似ており、「実行時間はヒープ以外のものに完全に支配されているように見えます」(@Alpedar)。しかし、コードでそれを示す証拠を見つけることができませんでした。コードは開いているので、テストの結果に影響を与える可能性のあるものがあれば、教えてください。


多分私は何か間違ったことをしましたが、A.Rexの anwserの比較に基づいてテストを書きました

  • フィボナッチヒープ
  • D-Ary-ヒープ(4)
  • バイナリヒープ
  • リラックスヒープ

すべてのヒープの実行時間(完全なグラフのみ)は非常に近かった。テストは、1000、2000、3000、4000、5000、6000、7000、および8000の頂点を持つ完全なグラフに対して行われました。各テストで50個のランダムグラフが生成され、出力は各ヒープの平均時間です。

出力については申し訳ありませんが、テキストファイルからいくつかのグラフを作成する必要があったため、それほど冗長ではありません。


結果は次のとおりです(秒単位):

ヒープ結果テーブル


4
それぞれの場合にエッジはいくつありますか?そして、どのアルゴリズムを正確に実行していますか?何を扱っているのかわからない場合、結果は意味をなしません。
kokx 2013年

残念ながら、すべてのグラフが完成しているので、各ケースのエッジの数を計算できます。「あなたは正確に走っていますか」という意味です。彼らはテーブルの頭にいます。
ギルヘルメトレスカストロ

22
これは、実行時間の全体がヒープ以外の要素に支配されているように見えます(グラフまたはIOの生成の可能性があります)。これらのほぼ同じ結果は信じられないほどです。
Alpedar 2013年

2
おそらく、時間は他の何かによって支配されていますが、それはIOやグラフの生成ではないと確信しています。とにかく、ソースコードが利用可能であり、誰かがエラーを見つけて測定値を修正した場合、私は非常に喜んでいます。
ギルヘルメトレスカストロ

これらのテストは、まったく異なるものを測定しているようです。実行したテストについてコメントしていただけますか?距離が幾何学的/ユークリッドの場合、完全なグラフの最短経路問題はO(1)であることを覚えておいてください。
Gaminic 2014

0

また、フィボナッチヒープで小さな実験を行いました。詳細はこちらのリンク:Experimenting-with-dijkstras-algorithm。私は「フィボナッチヒープJava」という用語をググって、フィボナッチヒープのいくつかの既存のオープンソース実装を試しました。一部にはパフォーマンスの問題があるようですが、かなり良いものもあります。少なくとも、私のテストでは、彼らは素朴でバイナリヒープのPQパフォーマンスを上回っています。多分彼らは効率的なものを実装するのを助けることができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.