web-dev-qa-db-ja.com

2つのBSTを効率的にマージする方法は?

BSTのプロパティを維持しながら2つの二分探索木をマージする方法は?

ツリーから各要素を取得して他の要素に挿入することにした場合、このメソッドの複雑さはO(n1 * log(n2))になります。ここで、n1はツリーのノードの数(たとえばT1)です。分割され、n2は他のツリーのノードの数です(たとえばT2)。この操作の後、1つのBSTのみにn1 + n2ノードがあります。

私の質問は、O(n1 * log(n2))よりも優れた方法はありますか?

25
gowth08

もう少し詳細なNaaffの答え:

  • BSTをソートされたリストにフラット化するのはO(N)です。
    • これは、ツリー全体での「順序どおりの」反復です。
    • 両方のためにそれをすることはO(n1 + n2)です
  • 2つのソート済みリストを1つのソート済みリストにマージするのはO(n1 + n2)です。
    • 両方のリストの先頭へのポインタを保持します
    • 小さい方の頭を選び、そのポインターを進めます
    • これがマージソートのマージの仕組みです
  • ソートされたリストから完全にバランスの取れたBSTを作成するのは、O(N)です。
    • アルゴリズムについては、以下のコードスニペットを参照してください[1]
    • この場合、ソートされたリストのサイズはn1 + n2です。したがって、O(n1 + n2)
    • 結果のツリーは、リストを二分探索する概念的なBSTになります。

O(n1 + n2)の3つのステップは、O(n1 + n2)になります。

同じ桁のn1とn2の場合、O(n1 * log(n2))よりも優れています。

[1]ソートされたリストからバランスの取れたBSTを作成するためのアルゴリズム(Python):

def create_balanced_search_tree(iterator, n):
    if n == 0:
        return None
    n_left = n//2
    n_right = n - 1 - n_left
    left = create_balanced_search_tree(iterator, n_left)
    node = iterator.next()
    right = create_balanced_search_tree(iterator, n_right)
    return {'left': left, 'node': node, 'right': right}
26
yairchu
  • 木を平らにしてソートされたリストにします。
  • ソートされたリストをマージします。
  • マージされたリストからツリーを作成します。

IIRC、つまりO(n1 + n2)。

21
Stu

両方のツリーをソートされたリストにフラット化し、リストをマージしてから新しいツリーを作成するのはどうですか?

8
Naaff

ジョナサン、

ソート後、長さn1 + n2のリストがあります。それから二分木を構築するには、log(n1 + n2)の時間がかかります。これはマージソートと同じですが、各再帰ステップで、マージソートアルゴリズムのようにO(n1 + n2)項がない点が異なります。したがって、時間計算量はlog(n1 + n2)です。

ここで、問題全体の複雑さはO(n1 + n2)です。

また、2つのリストが同等のサイズである場合、このアプローチは適切だと思います。サイズが比較できない場合は、小さなツリーのすべてのノードを大きなツリーに挿入するのが最善です。これにはO(n1 * log(n2))時間がかかります。たとえば、サイズが10のツリーとサイズが1024のツリーが2つある場合、ここではn1 + n2 = 1034ですが、n1log(n2)= 10 * 10 = 100です。したがって、アプローチは2つのツリーのサイズに依存する必要があります。

1
genthu

O(n1 * log(n2))は、ソートされていないリストを2つマージしてBSTにした場合でも、平均的なシナリオです。リストがソートされたリストまたはBSTであるという事実を利用していません。

私によると、1つのBSTにn1個の要素があり、他のBSTにn2個の要素があると仮定しましょう。次に、1つのBSTをO(n1)のソート済み配列リストL1に変換します。

マージされたBST(BST、配列)

if(Array.size == 0)return BST if(Array.size == 1)要素をBSTに挿入します。 BSTを返します。

左側の要素<BST.rootnodeおよび右側の要素> = BST.rootnodeがIndexと言う配列内のインデックスを見つけます。 if(BST.rootNode.leftNode == null)// i.e左ノードなし{インデックスから0までのすべての配列をBSTの左側に挿入し、} else {マージされたBST(BST.leftNode、Array {0 to Index})}

if(BST.rootNode.rightNode == null)// ie右ノードがありません{IndexからArray.sizeまでのすべての配列をBSTの右側に挿入します} else {マージされたBST(BST.rightNode、Array {Index to Array.size} )}

bSTを返します。

このアルゴリズムは、サブ問題を処理するために配列とBSTを分割するたびに、O(n1 * log(n2))よりも<<時間がかかります。


0
Manu