RBツリー、Bツリー、またはAVLツリーを選択するのはいつですか?


88

プログラマーとして、いつRBツリー、Bツリー、またはAVLツリーの使用を検討すべきですか?選択を決定する前に考慮する必要がある重要なポイントは何ですか?

誰かが各ツリー構造のシナリオを使用して、キーポイントを参照して他のツリー構造を選択する理由を説明できますか?


10
まあ、私はこの質問に感謝します-現在、fastutil IntAVLTreeSet対IntRBTreeSetの選択肢が提示されています。
ヤン

回答:


113

塩ひとつまみでこれを取る:

何千ものアイテムを管理していて、ディスクや低速のストレージメディアからそれらをページングしているときのBツリー。

ツリーで頻繁に挿入、削除、取得を行う場合のRBツリー。

挿入および削除が検索に比べてまれな場合のAVLツリー。


34
さらに詳細を追加するだけです。Bツリーは、多数のレコードを保持できるようにする子の数を可変にすることができますが、高さの短いツリーを維持します。RBツリーには、AVLツリーよりも挿入/削除を高速にする再バランスに関する厳格なルールがありません。逆に、AVLツリーはより厳密にバランスが取れているため、ルックアップはRBツリーよりも高速です。
pschang

RBツリーは、リバランスでのパフォーマンスO(1)も優れているため、ロールバックとロールフォワードを使用した永続的なデータ構造に適しています。

20

B +ツリーは、メインメモリでも、汎用の順序付けされたコンテナーデータ構造として適しています。仮想メモリが問題ではない場合でも、キャッシュの使いやすさはしばしば問題になり、B +ツリーはシーケンシャルアクセスに特に適しています。リンクリストと同じ漸近的なパフォーマンスですが、キャッシュの使いやすさは単純な配列に近くなります。このすべてとO(log n)の検索、挿入、削除。

ただし、B +ツリーには問題があります。たとえば、挿入/削除を実行するとアイテムがノード内を移動し、それらのアイテムへのポインターが無効になるなどです。「カーソルメンテナンス」を実行するコンテナライブラリがあります。カーソルは、リンクリストで現在参照しているリーフノードにアタッチされるため、自動的に修正または無効化できます。カーソルが1つまたは2つを超えることはめったにないため、うまく機能しますが、まったく同じように追加の作業が必要です。

もう1つは、B +ツリーが本質的にそれだけであることです。必要かどうかに応じて、非リーフノードを削除または再作成できると思いますが、バイナリツリーノードを使用すると、柔軟性が大幅に向上します。バイナリツリーはリンクされたリストに変換でき、ノードをコピーせずに戻すことができます。ポインタを変更するだけで、それを別のデータ構造として扱っていることを覚えておいてください。とりわけ、これは、ツリーのO(n)マージがかなり簡単になることを意味します。両方のツリーをリストに変換し、それらをマージしてから、再びツリーに変換します。

さらに別のことは、メモリの割り当てと解放です。バイナリツリーでは、これをアルゴリズムから分離できます。ユーザーはノードを作成してから挿入アルゴリズムを呼び出し、削除するとノードを抽出できます(ツリーからノードを切り離しますが、メモリを解放しないでください)。BツリーまたはB +ツリーでは、明らかに機能しません。データはマルチアイテムノードに存在します。必要な新しいノードの数がわかるまで、ノードを変更せずに操作を「計画」し、それらを割り当てることができる挿入メソッドを作成するのは困難です。

赤黒vs AVL?それが大きな違いをもたらすかどうかはわかりません。私自身のライブラリには、ノードを操作するためのポリシーベースの「ツール」クラスがあり、さまざまな変換を含む、二重リンクリスト、単純なバイナリツリー、スプレーツリー、赤黒ツリー、および盗み取り用のメソッドがあります。これらのメソッドのいくつかは、私がいつか退屈していたために実装されただけです。treapメソッドをテストしたことすらありません。AVLではなく赤黒木を選んだ理由は、アルゴリズムを個人的によく理解しているからです。これは、アルゴリズムが単純であることを意味するのではなく、私がより親しんでいるのは単なる歴史の変化です。

最後にもう1つ、私は元々B +ツリーコンテナーを実験として開発しました。これは実際に終わったことのない実験の1つですが、他の人に繰り返すことを勧めるようなものではありません。必要なのが順序付けられたコンテナーだけである場合、最良の答えは、既存のライブラリーが提供するものを使用することです(C ++のstd :: mapなど)。私のライブラリは何年​​にもわたって進化し、安定するまでにかなりの時間がかかりました。そして、最近、それが技術的に移植不可能であることを発見しました(WRT offsetofの未定義の動作に依存します)。



0

データ構造を選択するとき、次のような要素をトレードオフします

  • 検索速度v更新速度
  • 構造がワーストケースの操作(ソートされた順序で到着するレコードの挿入など)にどれだけうまく対応するか
  • 無駄なスペース

まず、Robert Harveyが参照するWikipediaの記事を読むことから始めます。

実用的には、Javaなどの言語で作業する場合、平均的なプログラマーは提供されているコレクションクラスを使用する傾向があります。パフォーマンスチューニングアクティビティで、コレクションのパフォーマンスに問題があることがわかった場合は、別の実装を探すことができます。ビジネス主導の開発で最初に考慮しなければならないことはほとんどありません。このようなデータ構造を手動で実装する必要があることは非常にまれです。通常、使用できるライブラリがあります。


1
公平を期すために、OPはwhen should I consider usingではなくを尋ねましたwhen should I consider implementing。最後の段落は真実ですが、この質問のコンテキストではあまり価値がありません。ライブラリを使用する場合でも、ビジネスのニーズに最適な構造を効果的に選択するには、アルゴリズムを理解する必要があります。
Dan Bechard、2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.