web-dev-qa-db-ja.com

バイナリ検索ツリーの定義で重複キーは許可されていますか?

バイナリ検索ツリーの定義を見つけようとしていますが、どこでも異なる定義を見つけ続けています。

一部のサブツリーでは、左の子キーはルート以下であると言う人もいます。

あるサブツリーについて、正しい子キーはルート以上であると言う人もいます。

そして、私の古い大学のデータ構造の本には、「すべての要素にキーがあり、同じキーを持つ要素は2つもない」と書かれています。

Bstの普遍的な定義はありますか?特に、同じキーの複数のインスタンスを持つツリーをどう処理するかに関して。

編集:たぶん私ははっきりしていなかった、私が見ている定義は

1)左<=ルート<右

2)左<ルート<=右

3)重複キーが存在しないように、左<ルート<右。

126
Tim Merrifield

多くのアルゴリズムは、重複が除外されることを指定します。たとえば、MIT Algorithms bookのアルゴリズム例は、通常、重複のない例を示します。重複をノードでリストとして、または特定の方向に実装することは非常に簡単です。)

ほとんど(私が見た)は、左の子を<=として、右の子を>として指定します。実際には、右または左の子のいずれかをルートノードと等しくすることができるBSTでは、重複ノードが許可されている検索を完了するために、追加の計算手順が必要になります。

ノードの片側に「=」値を挿入するには、ノードを子として配置するためにその側でツリーを書き換えるか、ノードをグランドとして配置する必要があるため、ノードでリストを使用して複製を保存することをお勧めします-child、以下のある時点で、検索効率の一部を排除します。

覚えておく必要があります。教室の例のほとんどは、概念を描写して提供するために簡略化されています。彼らは多くの現実世界の状況でしゃがむ価値はありません。しかし、「すべての要素にキーがあり、2つの要素に同じキーがない」というステートメントは、要素ノードでのリストの使用に違反していません。

それで、あなたのデータ構造の本が言ったことに行ってください!

編集:

バイナリ検索ツリーのユニバーサル定義では、2つの方向のいずれかでデータ構造を走査することに基づいてキーを保存および検索します。実際的な意味では、値が<>の場合、2つの「方向」のいずれかでデータ構造を走査します。したがって、その意味では、値の重複はまったく意味をなしません。

これはBSPまたはバイナリ検索パーティションとは異なりますが、すべてが異なるわけではありません。検索するアルゴリズムには、「旅行」の2つの方向のいずれかがあります。または、(成功したかどうかにかかわらず)実行されます。重複が実際に異なるため、元の答えが「普遍的な定義」トピック(バイナリ検索の一部としてではなく、検索の成功後に処理するもの。)

71
Chris

バイナリ検索ツリーが赤黒ツリーである場合、または任意の種類の「ツリー回転」操作を予定している場合、ノードの重複により問題が発生します。あなたのツリーのルールがこれだと想像してください:

左<ルート<=右

ここで、ルートが5、左の子がnil、右の子が5である単純なツリーを想像してください。ゼロであること。これで、左側のツリーにあるものはルートに等しくなりますが、上記のルールはleft <rootであると想定しています。

私は赤/黒の木がときどき順不同で横断する理由を理解しようとして何時間も費やしました。問題は上記で説明したものでした。誰かがこれを読んで、将来のデバッグの時間を節約できることを願っています!

44
Rich

3つの定義はすべて受け入れられ、正しいものです。 BSTのさまざまなバリエーションを定義します。

あなたの大学のデータ構造の本は、その定義が唯一の可能性ではないことを明確にすることに失敗しました。

確かに、複製を許可すると複雑さが増します。 「左<=ルート<右」という定義を使用し、次のようなツリーがある場合:

      3
    /   \
  2       4

このツリーに「3」の重複キーを追加すると、次の結果になります。

      3
    /   \
  2       4
    \
     3

重複は連続したレベルではないことに注意してください。

上記のようにBST表現で重複を許可する場合、これは大きな問題です。重複は任意のレベル数で区切られる可能性があるため、重複の存在を確認することは、ノードの直接の子を確認するほど簡単ではありません。

この問題を回避するオプションは、重複を構造的に(別個のノードとして)表現せず、代わりにキーの出現回数をカウントするカウンターを使用することです。前の例には、次のようなツリーがあります。

      3(1)
    /     \
  2(1)     4(1)

重複した「3」キーを挿入すると、次のようになります。

      3(2)
    /     \
  2(1)     4(1)

これにより、検索、削除、および挿入の操作が簡略化されますが、余分なバイト操作とカウンター操作が犠牲になります。

33
duilio

BSTでは、ノードの左側にあるすべての値は、ノード自体より小さい(または等しい、後述)。同様に、ノードの右側にあるすべての値は、ノードの値より大きい(または等しい)(a)

一部のBSTは、重複する値を許可することを選択する場合があるため、上記の「または等しい」修飾子が使用されます。

次の例で明確になります。

            |
      +--- 14 ---+
      |          |
+--- 13    +--- 22 ---+
|          |          |
1         16    +--- 29 ---+
                |          |
               28         29

これは、重複を許可するBSTを示しています。値を見つけるには、ルートノードから開始し、検索値がノード値よりも小さいか大きいかに応じて、左または右のサブツリーを下ることがわかります。

これは、次のような方法で再帰的に実行できます。

def hasVal (node, srchval):
    if node == NULL:
         return false
    if node.val == srchval:
        return true
    if node.val > srchval:
        return hasVal (node.left, srchval)
    return hasVal (node.right, srchval)

そしてそれを呼び出す:

foundIt = hasVal (rootNode, valToLookFor)

同じ値の他のノードの値を見つけたら、検索を続ける必要があるため、複製は少し複雑になります。


(a) could特定のキーの検索方法を調整したい場合は、実際に逆方向に並べ替えます。 BSTは、昇順か降順かに関係なく、ソートされた順序を維持するだけで済みます。

21
paxdiablo

Cormen、Leiserson、Rivest、Steinによる書籍「Introduction to algorithm」第3版では、バイナリ検索ツリー(BST)が重複を許可として明示的に定義されています。これは、図12.1および次のページ(287ページ)で確認できます。

「バイナリ検索ツリーのキーは、常にバイナリ検索ツリーのプロパティを満たすような方法で格納されます。xをバイナリ検索ツリーのノードにします。yxの左サブツリーのノード、次にy:key <= x:keyyxの右側のサブツリーのノードである場合、y:key >= x:key。」

さらに、red-blackツリーが308ページで次のように定義されます。

「赤黒木は、ノードごとに1ビットのストレージを追加したバイナリ検索木です。色」

したがって、この本で定義されている赤黒木は重複をサポートしています。

8
Laurent Martin

赤黒ツリーの実装に取り​​組んでいると、赤黒挿入の回転で制約を緩める必要があることに気付くまで、複数のキーでツリーを検証する際に問題が発生していました

left <= root <= right

私が見ていたドキュメントでは重複キーを許可しておらず、それを説明するために回転方法を書き直したくなかったので、ノード内で複数の値を許可するようにノードを変更し、ツリー。

3
Jherico

定義はすべて有効です。実装に一貫性がある限り(常に、等しいノードを右側に配置するか、常に左側に配置するか、許可しないようにします)、問題ありません。それらを許可しないのが最も一般的だと思いますが、許可され、左または右のいずれかに配置される場合、それはまだBSTです。

2
SoapBox

あなたが言ったこれらの3つのことはすべて真実です。

  • キーは一意です
  • 左側には、これよりも小さいキーがあります
  • 右側にはこれよりも大きなキーがあります

ツリーを逆にして小さなキーを右側に配置することもできますが、実際には「左」と「右」の概念はまさにそれです。または正しいので、それは本当に重要ではありません。

2
nickf

1.)左<=ルート<右

2.)左<ルート<=右

3.)重複キーが存在しないように、左<ルート<右。

アルゴリズムの本を探し出さなければならないかもしれませんが、頭の一番上(3)は標準形式です。

(1)または(2)は、重複ノードの許可を開始したときにのみ発生しますおよび(リストを含むノードではなく)ツリー自体に重複ノードを配置します。

1
Robert Paulson

重複キー•同じキーを持つデータ項目が複数ある場合はどうなりますか? –これは、赤黒木でわずかな問題を示します。 –同じキーを持つノードが、同じキーを持つ他のノードの両側に分散していることが重要です。 –つまり、キーが50、50、50の順序で到着した場合、2番目の50は最初のキーの右側に、3番目の50は最初のキーの左側に移動します。 •それ以外の場合、ツリーは不均衡になります。 •これは、挿入アルゴリズムのある種のランダム化プロセスで処理できます。 –ただし、同じキーを持つすべてのアイテムを見つける必要がある場合、検索プロセスはより複雑になります。 •同じキーを持つアイテムを禁止する方が簡単です。 –この議論では、重複は許可されていないと仮定します

重複キーを含むツリーのノードごとにリンクリストを作成し、リストにデータを保存できます。

1
mszlazak

リレーション<=を順序付けする要素は 全順序 であるため、リレーションは再帰的である必要がありますが、通常、バイナリ検索ツリー(別名BST)は重複のないツリーです。

それ以外の場合、重複がある場合は、同じ削除機能を2回以上実行する必要があります!

0
AlbertoMinetti