Avlツリー上の赤黒木


108

AVLと赤黒の木は、ノードの赤と黒を除いて、どちらも自己バランスです。AVLツリーの代わりに赤黒木を選択する主な理由は何ですか?赤黒木の用途は何ですか?



1
余談ですが、Rust開発者は、標準の順序付けされたマップに、これらのいずれかではなくBツリーを使用することを選択しました。
トムアンダーソン、

回答:


122

AVLツリーの代わりに赤黒木を選択する主な理由は何ですか?

どちらの赤黒の木AVL木が最も一般的に使用されているバランス二分探索木と彼らが保証さで挿入、削除およびルックアップをサポートO(logN) time。ただし、次の2つの比較点があります。

  • AVLツリーはより厳密にバランスが取れているため、より高速なルックアップを提供します。したがって、ルックアップの多いタスクでは、AVLツリーを使用します。
  • 挿入を多用するタスクには、赤黒ツリーを使用します。
  • AVLツリーは、各ノードのバランス係数を格納します。これにはO(N)余分なスペースが必要です。ただし、ツリーに挿入されるキーが常に0よりも大きいことがわかっている場合は、キーの符号ビットを使用して赤黒ツリーの色情報を格納できます。したがって、そのような場合、赤黒木は余分なスペースを取りません。

レッドブラックツリーの用途は何ですか?

赤黒木はより一般的な目的です。追加、削除、およびルックアップは比較的うまく機能しますが、AVLツリーは、追加/削除が遅くなる代わりに、ルックアップが高速になります。赤黒木は以下で使用されます:

  • Javaの:java.util.TreeMapjava.util.TreeSet
  • C ++ STL(ほとんどの実装):マップ、マルチマップ、マルチセット
  • Linuxカーネル:完全に公平なスケジューラー、linux / rbtree.h

43
In general, the rotations for an AVL tree are harder to implement and debug than that for a Red-Black tree.真実ではない。
Jingguo Yao

9
理解を深めるために、C ++標準はそのことstd:: mapを義務付けておらず、友人たちは特定の構造を使用しています。libstdc ++とDinkumwareは少なくとも赤黒木を使用していますが、それは実装に委ねられており、実際には正しいようです。
mbozzi

25
AVLツリーの各ノードに格納されるバランス係数は2ビット(-1 / 0 / +1)です。赤黒ツリーは、各ノードに1ビットの色情報を格納します。したがって、合計で両方のツリーは追加情報のためにO(N)メモリを必要とします。
Seppo Enarvi 2017年

5
「挿入の多いタスクには、赤黒ツリーを使用してください。」どうして?AVLツリーの挿入では、最悪の場合1回転しかかかりませんが、Red Blackツリーでは2回転できます。
ダニエル

3
これは、BSTパフォーマンスに関するBen Pfaffの2003年の分析に従って更新する必要があります。AVLツリーはより汎用的で、パフォーマンスが向上します。Java、C ++、およびLinuxカーネルがより遅い実装を選択した正確な歴史的理由は、追跡するのに興味深いでしょう。
デビッドマクマナモン2018年

16

この記事を読んでみてください

違い、類似点、パフォーマンスなどについて、いくつかの良い洞察を提供します。

これは記事からの引用です:

RBツリーは、AVLツリーと同様に、自己バランスです。どちらもO(log n)検索と挿入のパフォーマンスを提供します。

違いは、RBツリーは挿入操作ごとにO(1)回転を保証することです。これが、実際の実装で実際にパフォーマンスにかかるコストです。

単純化されたRBツリーは、動的ノード構造のオーバーヘッドを持ち越さずに、概念的に2〜3ツリーであることからこの利点を獲得します。物理的にRBツリーはバイナリツリーとして実装され、赤/黒フラグは2-3の動作をシミュレートします

私自身が理解している限り、AVLツリーとRBツリーはパフォーマンスの点ではそれほど遠くありません。RBツリーは単にBツリーのバリアントであり、バランシングはAVLツリーとは異なる方法で実装されます。


1
AVLAKツリーであるAFIAKには、挿入ごとにO(1)ローテーションもあります。RBツリーとAVLの場合-1つの挿入は1または0の回転を持つ場合があります。ローテーションが発生すると、アルゴリズムは停止します。それが起こらない場合、通常、アルゴリズムはノードをツリーの下からルートまでチェック/再ペイントし続けます。したがって、ローテーションO(1)は、残りのアイテムO(log(n))のスキャンを排除するため、より良い場合があります。AVLツリーは平均してより多くのローテーションを行うため、通常、AVLツリーはRBツリー2 log(N)よりもバランスが〜1.44 log(N)優れています。
セルゲイシャンダー

4

パフォーマンスの違いに関する私たちの理解は年を重ねるごとに向上し、今ではAVLで赤黒木を使用する主な理由は、CLRSでカバーされていないためか、あまり一般的ではないため、適切なAVL実装にアクセスできないことです。

現在、両方のツリーはランクバランスツリーの形式と見なされていますが、実際のテストでは赤黒木は常に約20%遅くなっています。または、順次データが挿入されると、30〜40%遅くなります。

したがって、AVLツリーではなく赤黒木を研究した人は、赤黒木を選択する傾向があります。赤黒の木の主な用途は、ウィキペディアのエントリで詳しく説明されています


1
おかしい!私の読書では、libavlの記事でAVLとRBは直接対比されているように思われ、どちらも一般的に他のどれよりも明らかに優れています(どちらがワークロードに依存するか)。AVLが全体的に約20%速いという主張はどこにもありません。
Stefan

3

ここでの他の答えは、RBツリーとAVLツリーの長所と短所をまとめたものですが、この違いは特に興味深いものでした。

AVLツリーは一定の償却更新コストをサポートしていません[ただし、赤黒ツリーはサポートしています]

出典:Mehlhorn&Sanders(2008)(セクション7.4)

したがって、RBツリーとAVLツリーの両方で、ルックアップ、挿入、削除にO(log(N))最悪の時間が保証されますが、ノードの挿入または削除後の AVL / RBプロパティの復元は、O(1)の償却時間で実行できます。赤黒の木。


AVLツリー挿入の償却コストは同じか類似していますが、よりバランスの取れたツリーが生成されると思います(1.44log(N)対2log(N))。同時に、AVLツリーでの削除には、より多くのローテーションが必要になる場合があります。私見、これはWAVL en.wikipedia.org/wiki/WAVL_tree
セルゲイシャンダル

1

プログラマは通常、メモリを動的に割り当てることを好みません。avlツリーの問題は、「n」要素の場合、ツリーの高さを格納するために少なくともlog2(log2(n))...(height-> log2(n))ビットが必要なことです。したがって、膨大なデータを処理している場合、各ノードで高さを格納するために割り当てるビット数がわかりません。

たとえば、高さの格納に4バイトの整数(32ビット)を使用する場合。最大の高さは2 ^ 32になる可能性があるため、ツリーに格納できる要素の最大数は2 ^(2 ^ 32)です(非常に大きいようですが、このデータの時代では、大きすぎるとは思いません)。したがって、この制限を超えると、高さを格納するためにより多くのスペースを動的に割り当てる必要があります。

これは私の大学の教授が提案した答えです。私が理にかなっていると思います。

編集:AVLツリーは赤黒ツリーと比較してバランスが取れていますが、挿入および削除中に回転が多くなる可能性があります。したがって、アプリケーションに頻繁な挿入と削除が頻繁に含まれる場合は、Red Blackツリーをお勧めします。また、挿入と削除の頻度が低く、検索の頻度が高い場合は、レッドブラックツリーよりもAVLツリーを優先する必要があります。--Source GEEKSFORGEEKS.ORG


1
これはおもしろいが実用的ではないと思います。最もコンパクトなケースでは、高さを割り当てるために最も効率的なビット数を選択するのは難しい作業ですが、実際には、1バイト未満の残りのスペースは必ず使用されず、残りはすべて残ります。 4バイトまたは8バイトのスペースでも、ほぼ確実に未使用になります。パフォーマンス上の理由から、メモリは整列されずに割り当てられないため、少量のスペースを再利用する利点が大幅に無効になります。子へのポインタと値は24バイトを占めます。さらに8つは、実際的なコストがかかる可能性は低いです。
Mumbleskates

4
you need need atleast log2(log2(n))...(height->log2(n)) bits to store the height of [an AVL] treeAVLツリーのノードの高さを実装する必要はありません。あなたが旧姓1ビットの各ノードのための追加情報のを(Iが最大AM最高サブツリーと(兄弟)))。AVとLによって提示されたように、2つのビットを追加する(子は左と右の方が高い)と、従来の方法よりも便利です
greybeard

4
2 ^(2 ^ 32)要素はたくさんあります...宇宙全体のすべての単一の分子、それらの分子の可能なすべてのペア、および可能なすべてのトリプルを保存することができますが、それでも遠隔に近づくことさえできませんその数の3乗根の100万分の1の小さな割合のごく一部に含まれます。
セミコロン'19年

4
これは非常に誤解を招くものです。まず、AVLツリーのノードに高さを格納する必要はありません。第2に、たとえ通常の利用可能なメモリ量が毎年2倍になったとしても、ツリーの高さが32ビットに格納できる量を超えるまで、40億年あります。
Gassa 2017年

3
2 ^(2 ^ 32)オブジェクトは、途方もなく、めちゃくちゃに、今私たちが想像できるどんなコンピュータよりも絶対に多くあります。2 ^ 40程度です。もう一度算数を確認してください。
ステファンライヒ2017

-1

AVLツリーの再バランスは、以下のプロパティを満たす必要があります。(Wikiリファレンス-AVLツリー

AVLツリーでは、ノードの2つの子サブツリーの高さは最大で1つだけ異なります。常に2つ以上異なる場合は、このプロパティを復元するためにリバランスが行われます。

したがって、これはAVLツリーの全体的な高さが狂ってしまうことはあり得ないことを意味します。つまり、AVLツリーを使用すると、ルックアップが改善されます。また、高さを狂わせないように追加の操作(回転)を行う必要があるため、ツリーの変更操作は少しコストがかかる可能性があります。


他の多くの場所で言及されていますが、この回答があまり良くない理由は、AVLツリーとRBツリーが非常に類似した制約を効果的に維持しているためです-RBツリーは必要な高さの2.0倍を超えないため、 1.44年頃。結果として、AVLツリーはわずかに頻繁にローテーションしますが、ローテーションあたりのコストは基本的に同じです。費用はかかりません。
Mumbleskates
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.