バイナリ ツリーのスキルを磨くためにいくつかの演習を行った結果、ウィキペディア: スプレー ツリーで概説されているように、スプレー ツリーを実装することにしました。
私が得ていないことの1つは、挿入に関する部分です。
それは言います:
まず、splay ツリーで x を検索します。x がまだ存在しない場合、それは見つかりませんが、その親ノード y は見つかりません。次に、y に対してスプレイ操作を実行し、y をスプレイ ツリーのルートに移動します。3 番目に、適切な方法で新しいノード x をルートとして挿入します。このように、y は新しいルート x の左または右の子になります。
私の質問は次のとおりです。上記のテキストは、記事の他の例に比べて非常に簡潔に見えますが、それはなぜですか? ここにはいくつかの落とし穴が残っているようです。たとえば、y ノードをルートまで展開した後、やみくもにルートを x に置き換えて、y を左または右の子として x に追加することはできません。
値がツリーにまだ存在していないと仮定しましょう。
私はこの木を持っています:
10
/ \
5 15
/ \ \
1 6 20
8 を挿入します。上記の説明で、6 ノードを見つけます。通常のバイナリ ツリーでは、6 ノードの右の子として 8 が追加されますが、ここではまず、ルートまでの 6 ノード:
6
/ \
5 10
/ \
1 15
\
20
次に、これら2つのいずれかが明らかに間違っています。
8 8
\ /
6 6
/ \ / \
5 10 5 10
/ \ / \
1 15 1 15
\ \
20 20
6 is not greater than 8 10 is not less than 8
最初にスプレイを行い、次にルートとして新しい値を正しく追加する唯一の方法は、次の基準をチェックする必要があることを意味するように思えます(スプレイされたノードを新しいルートの左の子として追加するため):
- ルートに展開したノードは、新しいルートよりも小さい (6 < 8)
- ルートに展開したノードの右端の子も、新しいルート (20 8) より小さいです。
ただし、展開したノードを分割する場合、適切な子を取得して新しいノードの適切な子として追加すると、次のようになります。
8
/ \
6 10
/ \
5 15
/ \
1 20
しかし、この単純な変更で常に正しいツリーが得られるのでしょうか? 例を思いつくのに苦労していますが、これは次のようになる可能性があります。
- 追加したい新しい値は、一時ルート (ルートに展開したノード) よりも高いですが、一時ルートの右側の子の左端の子よりも高いですか?
すなわち。広げた後、基本的にこのように見えるツリーですが、ルートを置き換える前は?
10
/ \
5 15
/ \
11 20
13 を追加すると、新しいツリーは次のようになります。
13
/ \
10 15
/ / \
5 11 20 <-- 11, on the wrong side of 13
または、これは決して起こり得ませんか?
私の 2 番目の質問は次のとおりです。操作を次のように書き直す方がはるかに簡単ではないでしょうか。
まず、splay ツリーで x を検索します。x がまだ存在しない場合、それは見つかりませんが、その親ノード y は見つかりません。次に、新しいノードを親ノードの左または右の子として追加します。3 番目に、追加したノードでスプレイ操作を実行し、新しい値をスプレイ ツリーのルートに移動します。
私が変更したものを示すために私のものを強調してください。