木の高さは予測可能ですroundUp(log2(nodes))
。右のサブツリーがでないこともわかっています。は、左のサブツリーよりも大きい - |LS| >= |RS|
です。さらに、ツリーを完璧にするために欠けているノードの数を計算することができます:2^(height - 1) - arr.length
。これは、私たちは、サブツリーの中のノードをどのように分配するかを予測することができます:
findRoot(int[] arr , int maxLeaves , int maxLevelL)
//maxLeaves is the number of leaves on the maximum-level
int l = min(maxLevelL/2 , maxLeaves)
return (arr.length - maxLeaves)/2 + l
node buildTree(int[] arr , int maxLeaves , int maxLevelL)
if maxLevelL == 0
return null
node result
int rootidx = findRoot(arr , maxLeaves)
result.val = arr[rootidx]
result.left = buildTree(arr.subarray(0 , rootidx) , Math.min(maxLeaves , rootidx - 1) , maxLevelL/2)
result.right = buildTree(arr.subarray(rootidx + 1 , arr.length) , Math.max(0 , maxLeaves - rootidx - 1) , maxLevelL/2)
return node
基本的な考え方は以下の通りです:すべての完全な分探索木は、BSTの再帰的定義については、一つの特性を共有:LS
とRS
が残っている(LS , R , RS) OR null
、右サブツリーはBSTとしても定義されています。 LS
とRS
は完全であり、少なくとも1つは完璧でなければなりません。我々は2つのどれが完璧であるかを簡単に予測することができます:最高レベルではm
ノードに適合しますが、配列内には完全なツリーを構築するためにノードx
がありません。したがって:
if m - x == m/2 then both are complete and the height of RS is height(LS) - 1
if m - x < m/2 RS is perfect, LS only complete but not perfect
if m - x > m/2 LS is perfect, RS only complete but not perfect
if m - x == 0 both LS and RS are perfect and of equal height
我々は、次のルールを使用して、ツリーのルートを見つけることができる: 左(l
)上のノードの数を計算しheighestレベルに配置される右(r
)サブツリー。今、私たちは簡単に、木からそれらのノードを削除し、完璧なBSTのルートを計算し、後で暗黙的に戻ってツリーに左と右のノードを追加することができますroot = (arr.length - (l + r))/2 + l
E.g.:
Input: 1 2 3 4 5
Nodes on maxLevel: 2
maxLevelL: 4
l = 2
r = 0
root_idx = (arr.length - (l + r))/2 + l =
= (5 - 2)/2 + 2 =
= 3
Apply this algorithm recursively to define subtrees:
...
result:
4
/ \
2 5
/ \
1 3
注: 私がテストしていませんこのコード。修正する必要がある数学的な不十分さがまだ含まれている可能性があります。しかし、論理は正しいです。これは、ある配列から別の配列へのインデックスの再マッピングの方法を表すにすぎない。実際の実装は、私が提供したコードとかなり異なって見えるかもしれません。
二度目のこの議論を持った後、ここでは完全なBSTの定義です:完全なバイナリツリーで
あらゆるレベルで、おそらく最後を除いて、完全に充填され、そして最後のすべてのノードレベルはできるだけ遠くにある。
from wikipedia
コンプリート分探索木は、ソートされた配列とその逆に、完全なBSTのユニークなマッピングを許可するいくつかの追加の制約、で、バランスの取れた分探索木のサブクラスです。完全なBSTは均衡のとれたBSTのサブクラスなので、はでバランスの取れたBSTを構築するのには十分ではありません。
EDIT:
上記のアルゴリズムは、直接アレイを構築するため、以下のように変更することができる。
- ツリーのルートインデックス
n
持つノードの左の子をインデックス0
- を有しますインデックス
(n + 1) * 2 - 1
- インデックス
n
を持つノードの右の子はインデックス(n + 1) * 2
を持っています
通常、これらのアクセス操作は1ベースのアレイ上で行われますが、私はこのように、我々は直接配列を生成するためにbuildTree
を再実装することができ利便
ための0ベースの配列に一致するようにそれらを変更しました:
node buildTree(int[] arr , int maxLeaves , int maxLevelL ,
int[] result , int nodeidx)
if maxLevelL == 0
return
int rootidx = findRoot(arr , maxLeaves)
//insert value into correct position of result-array
result[nodeidx] = arr[rootidx]
//build left subtree
buildTree(arr.subarray(0 , rootidx) , Math.min(maxLeaves , rootidx - 1) , maxLevelL/2 ,
result , (nodeidx + 1) * 2 - 1)
//build right subtree
buildTree(arr.subarray(rootidx + 1 , arr.length) , Math.max(0 , maxLeaves - rootidx - 1) , maxLevelL/2 ,
result , (nodeidx + 1) * 2)
arr
とは異なり、result
というサブアレイは決して使用しません。どのメソッド呼び出しでも、各ノードのインデックスは決して変更されません。
分割統治を使用して何かを暗示マッピングで行く:右側、左側の子のために、アレイの左側に暗示機能を適用し、ルートに要素数ラウンド(サイズ/ 2)、地図右の子供のために。 – Aziuth
@Aziuthこれは完全なBSTにはなりませんが、バランスの取れたBSTになります。完全なBSTは平衡BSTのサブクラスであり、同等のものではない。 – Paul