web-dev-qa-db-ja.com

どの自己平衡バイナリツリーをお勧めしますか?

私はHaskellを学び、演習として二分木を作っています。通常のバイナリツリーを作成したので、それを自己バランスに適応させたいと思います。そう:

  • どちらが最も効率的ですか?
  • どちらが実装が最も簡単ですか?
  • 最もよく使用されるのはどれですか?

しかし、決定的に重要なのはどれですか。

これは議論の余地があるため、ここに属していると思います。

18
dan_waterworth

Red-Black tree または AVL tree のいずれかから始めることをお勧めします。

赤黒ツリーは挿入が高速ですが、AVLツリーにはルックアップ用のわずかなエッジがあります。 AVLツリーはおそらく実装が少し簡単ですが、私の経験に基づいたものではありません。

AVLツリーは、挿入または削除のたびにツリーのバランスが取られることを保証します(1/-1より大きいバランス係数を持つサブツリーはありませんが、赤黒ツリーは、ツリーがいつでも合理的にバランスが取られることを保証します。

15
Quick Joe Smith

randomizedデータ構造で問題がなければ、代替案を検討します: Skip Lists

高レベルの観点から見ると、これはツリー構造ですが、ツリーとしてではなく、複数のリンク層を持つリストとして実装されています。

O(log N)の挿入/検索/削除が行われ、これらのトリッキーな再調整のケースすべてに対処する必要はありません。

ただし、関数型言語での実装を検討したことはありません。ウィキペディアのページには何も表示されないため、簡単ではない可能性があります(不変性に変換)

10
Matthieu M.

比較的簡単な構造から始めたい場合(AVLツリーと赤黒ツリーの両方が厄介です)、1つのオプションは、「ツリー」と「ヒープ」の組み合わせとして名前が付けられたトリープです。

各ノードは「優先度」の値を取得し、ノードの作成時にランダムに割り当てられることがよくあります。ノードはツリー内に配置されるため、キーの順序が優先され、優先順位値のヒープのような順序が尊重されます。ヒープのような順序付けは、親の両方の子の優先順位が親よりも低いことを意味します。

[〜#〜] edit [〜#〜]上記の「キー値内」を削除-優先度とキーの順序が一緒に適用されるため、一意のキーであっても優先度は重要です。

それは興味深い組み合わせです。キーが一意であり、優先順位が一意である場合、ノードのセットごとに一意のツリー構造があります。それでも、挿入と削除は効率的です。厳密に言うと、ツリーは実質的にリンクリストになるほど不均衡になる可能性がありますが、(標準のバイナリツリーとは異なり)順序どおりに挿入されたキーなどの通常の場合を含め、これは(標準のバイナリツリーと同様に)非常に起こりません。

5
Steve314

どちらが最も効率的ですか?

曖昧で答えにくい。計算の複雑さはすべて明確に定義されています。それが効率であなたが意味するものであるならば、本当の議論はありません。実際、すべての優れたアルゴリズムには証明と複雑さの要素があります。

「ランタイム」または「メモリ使用」を意味する場合は、実際の実装を比較する必要があります。次に、言語、ランタイム、OS、およびその他の要因が関係し、質問への回答が困難になります。

どちらが実装が最も簡単ですか?

曖昧で答えにくい。一部のアルゴリズムはあなたには複雑に見えるかもしれませんが、私にとってはささいなことです。

最もよく使用されるのはどれですか?

曖昧で答えにくい。最初に「誰が」ですか?これの一部?ハスケルだけ? CまたはC++はどうですか?第2に、調査を行うためのソースにアクセスできない独自のソフトウェアの問題があります。

しかし、決定的に重要なのはどれですか。

これは議論の余地があるので、ここに属していると思います。

正しい。他の基準はあまり役に立たないので、これで十分です。

多数のツリーアルゴリズムのソースを取得できます。何かを学びたいのなら、見つけたものをすべて実装するだけかもしれません。 「推奨」を求めるのではなく、見つけることができるすべてのアルゴリズムを収集してください。

ここにリストがあります:

http://en.wikipedia.org/wiki/Self-balancing_binary_search_tree

6つの人気のあるものが定義されています。それらから始めます。

5
S.Lott

スプレイツリーに興味がある場合は、アレンとマンローの論文で最初に説明されたと思われる、より単純なバージョンがあります。同じパフォーマンス保証はありませんが、「ジグザグ」リバランスと「ジグザグ」リバランスの処理の複雑さを回避します。

基本的に、検索するとき(削除する挿入ポイントまたはノードの検索を含む)、見つけたノードはルートに向かって直接ボトムアップで回転します(たとえば、再帰的検索機能が終了すると)。各ステップで、ルートに向かって別のステップを引き上げたい子が右の子であるか左の子であるかに応じて、左または右の回転を1つ選択します(回転方向を正しく覚えていれば、それぞれです)。

Splayツリーと同様に、最近アクセスしたアイテムは常にツリーのルートの近くにあるため、すばやくアクセスできます。よりシンプルになると、これらのAllen-Munroeのルートへの回転ツリー(私はそれらを呼ばれます-正式名称はわかりません)はより速くなる可能性がありますが、同じ償却パフォーマンス保証はありません。

1つのこと-このデータ構造は定義により、検索操作でも変化するため、おそらくモナディックに実装する必要があります。 IOWは関数型プログラミングには適していないかもしれません。

3
Steve314

非常にシンプルなバランスツリーは AAツリー です。これは不変で、実装が簡単です。そのシンプルさゆえに、そのパフォーマンスは依然として良好です。

高度な演習として、型システムタイプによって不変条件が適用されるバランスツリーのバリアントの1つを実装するために GADTs を使用することができます。

2
Petr Pudlák