web-dev-qa-db-ja.com

赤黒木の挿入と削除を簡単に覚えるには?

標準のバイナリ検索ツリーとその操作を完全に理解するのは非常に簡単です。その理解のおかげで、私はそれらの挿入、削除、検索操作の実装を覚える必要さえありません。

私は今赤黒木を学んでおり、木をバランスよく保つためのその特性を理解しています。ただし、挿入と削除の手順を理解するのは非常に困難です。

新しいノードを挿入するときに、ノードを赤としてマークします(赤が赤黒ツリーの法則を超えないようにするためにできる最善の方法であるため)。新しい赤のノードは、「継続的な赤のノードなしの法則」に違反する可能性があります。次に、次のように修正します。

  1. その叔父の色をチェックし、赤の場合は、その親と叔父を黒としてマークし、祖父母に行きます。

  2. 右の子の場合は、親を左に回転します

  3. 親を黒、祖父母を赤としてマークしてから、祖父母を右に回転します。

完了(基本的に上記のように)。

多くの場所で、上記のようなRed-Blackツリーの挿入が説明されています。彼らはあなたにそれを行う方法を教えてくれます。しかし、なぜこれらの手順でツリーを修正できるのでしょうか。なぜ最初に左に回転し、次に右に回転するのですか?

誰かがCLRSよりもさらに明確に、なぜ明確に説明できるのでしょうか?ローテーションの魔法は何ですか?

本当に理解したいので、1年後には、本をレビューしなくても自分でRed-Blackツリーを実装できます。

ありがとう

33
Jackson Tale

私の(現在は削除されている)コメントは無視してください-岡崎のコードが役立つと思います。本(「完全に機能的なデータ構造」)がある場合は、26ページのテキストと図3.5(27ページ)をご覧ください。それより明確にするのは難しいです。

残念ながら オンラインで利用できる論文 にはその部分はありません。

図は重要なのでコピーしませんが、すべての異なるケースが基本的に同じものであり、非常にシンプルなMLコードによってそのホームを損なうことがわかります。

[更新]アマゾンでこれを見ることができるようです。 本のページ に移動し、画像の上にマウスを置き、検索ボックスに「赤黒」と入力します。これにより、25ページと26ページを含む結果が得られますが、それらを表示するにはログオンする必要があります(どうやら-チェックのためにログインを試していません)。

2
andrew cooke

受け入れられた回答で言及されている本にアクセスできないこのスレッドを読んでいる他の人のために、ここに私が受け入れられる説明的な回答になることを望みます。

回転すると、ツリーは色を変更する基準を満たした状態になります(子ノードには赤いおじがいます)。主な違いは2つあります。

  • どのノードが「子」であり、どのノードが「叔父」であるかが変更されました。
  • 親と叔父を黒に変更し、祖父母を赤に変更する代わりに、親を赤に、祖父母を黒に変更します。

子ノードに赤い叔父がいない場合、叔父ノードがすでに黒の場合、親を黒にすると祖父母の片側のみで黒の高さが1増えるため、回転する必要があります。これは赤黒木の高さ不変特性に違反し、ツリーのバランスを崩します。

次に、回転によってツリーがどのように変換されるかを見てみましょう。これにより、赤いおじの子ノードがあり、色を変更できます。これを完全に理解するには、これを引き出すことをお勧めします。

  • Xを、赤い親を持つ現在の赤いノードとします。
  • 回転前のxの赤の親をpとします(親が黒の場合は、既に完了しています)。
  • 回転前のxの黒の叔父をyとしましょう(叔父が赤の場合、回転は必要ありません。親と叔父を黒に、祖父母を赤に色変更するだけです)。
  • 回転前のxの黒の祖父母をgとします(親は赤なので、祖父母は黒でなければなりません。それ以外の場合、これは最初から赤黒の木ではありませんでした。)
  • 左(LL)または右(RR)の場合(つまり、xはpの左の子であり、pはgの左の子ですOR xはpの右の子であり、pはgの右の子です)、1回の回転後(LLの場合は右、RRの場合は左)、yは子になり、xはその叔父になります。したがって、子の親(子がy、親はgであるため)を赤に、子の祖父母(現在はp)を黒に変更します。
  • LRがある場合(xは左の子またはpであり、pはgの右の子です)またはRLケース(xはpの右の子であり、pはgの左の子です) )、2回転した後(LRの場合は右から左、RLの場合は左から右)、yは子になり、pはその叔父です。pは赤い叔父なので、色を変更できる場合があります。したがって、親(子は現在y、親はgであるため)を赤に、子の祖父母(現在はx)を黒に。

回転と色変更の前に、黒の祖父母が2つの赤のノードと0の黒ノードをA面(左または右)に、0の赤のノードと1つの黒ノードをB面(A面の反対側)に持っていました。回転と色の変更後、A側に1つの赤のノードと0の黒のノード、およびB側に1つの赤のノードと1つの黒のノードを持つ黒の祖父母ができました。いずれかのサブツリーの黒の高さを増やすことなく祖父母。

それが回転の魔法です。これにより、黒の高さを変更せずに、余分な赤いノードを別のブランチに移動でき、バイナリ検索ツリーのソート済みのトラバーサルプロパティを保持できます。

19
Serge Binette

ロジックはかなり単純です。 zが赤で、zの親が赤であるとします。zの叔父が赤の場合、手順1を実行して、(1)親がルートになるまで、問題のあるノードを上に押します。次に、ルートを黒にマークします。完了または(2)zの叔父は黒です。

(2)(a)zのいずれかがその親の左の子の場合、BSTのすべてのプロパティが満たされるため、ステップ3が最後のステップになります。できました。 (b)zはその親の正しい子です。ステップ2では、問題をケース(a)に変換します。次に、ステップ3を実行します。できました。

したがって、ロジックは、(1)と(2a)のどちらか先に到達した方に到達しようとすることです。これらは私たちが解決策を知っている状況です。

5
blackgreenmac

2-4(2-3-4)ツリーは赤黒ツリーに変換できます。そして、2-4本の木の理解ははるかに簡単です。 2〜4本のツリーで挿入と削除の操作を行うだけの場合、同じことを行うためのルールを覚えておく必要はないと感じます。さまざまな挿入と削除のシナリオを処理するためのソリューションを考え出すことができる、明確でシンプルなロジックが表示されます。

2〜4本の木を明確に理解したら、赤黒木を扱うときはいつでも、この赤黒木を2〜4本の木に精神的にマッピングして、自分でロジックを考え出すことができます。

2〜4本の木、赤黒木、および2〜4本の木の赤黒木へのマッピングを理解するのに非常に役立つ以下のビデオをいくつか見つけました。これらのビデオをご覧になることをお勧めします。

1)2-4本のツリーの場合: http://www.youtube.com/watch?v=JZhdUb5F7oY&list=PLBF3763AF2E1C572F&index=1

2)赤黒の木の場合: http://www.youtube.com/watch?v=JRsN4Oz36QU&list=PLBF3763AF2E1C572F&index=14

それぞれ1時間の長さの動画ですが、一読するだけの価値があると感じました。

1

おそらく、それは 左寄りの赤い黒い木 から始める価値があります。それらは興味深い単純化された実装を提供します。

0
Peteris