[プロ技] 二分探索木

woody_1227 オーナー 公式アカウント

Binary Search Tree
ログインすると、チェック機能を利用できるようになります。
二分探索木とは
・最も基本的な
 ・ …データを格納する が決められている木構造
 ・例えば、
  ・同一レベルのノードは左から右へ、
  ・レベルの上から下へ、
  ・値が大きくなるように格納
・二分探索木のデータ格納順序
 ・全てのノードについて、次の関係が成り立つように格納
  ・ノードの持つ値(キー)は、その
    左部分木のどのノードの値よりも か、または等しい
    右部分木のどのノードの値よりも か、または等しい
 ・つまり、
    左部分木の子孫の値 親の値 右部分木の子孫の値 [一般的にはこちら]
  が成り立っている
  ※もちろん、この順序関係は真逆でもよい
    左部分木の子孫の値≧親の値≧右部分木の子孫の値

二分探索木の有用性
・目的の値を持つノードを効率よく探索できる
 ・目的の値と現在注目しているノードの値を比較
  ・目的の値の方が大きい
   →目的の値は を再帰的に探す
  ・目的の値の方が小さい
   →目的の値は を再帰的に探す
 ・たったこれだけ!

二分探索木の探索効率
・ノード数nの二分探索木を考える
 ・目的の値を検索する際の計算量は?→ によって変わる
・最も探索効率が良い形は? ・最も探索効率が悪い形は?
・目的の値を探索する際の最大計算量を見積もりたい
 ・最大計算量=探索時の最大比較回数← に等しい(これは、ほぼ自明ですね)
・ノード数がnであるとき、探索に必要な計算量を考察しよう
 ・まずは、最良の場合
  →左右の部分木がバランスしている二分探索木( )
 ・では、ノード数nの平衡二分木の高さHはどうなるでしょう?
  ・Hをnの関数で表したい
   H = f(n)
・高さHの平衡二分木に収容できる最大ノード数nmaxは?
 ・木のレベルが深くなるごとに、子ノードは に増やせる
 ノードの総数は、初項1公比2の等比数列の第H項までの和 一般に

・高さHの平衡二分木に収容できる最大ノード数nmaxは
  nmax = 2^H - 1
 なので、高さHは
  H = log2(nmax + 1)
 ノード数nの平衡二分木の高さH(n)はn≦nmaxだから
  H(n)=log2(n + 1) log2(nmax + 1)
 二分探索木が平衡に分岐のとき、探索計算量は
  O( ) … これが最良の場合

・では、最悪の場合は
 ・左右どちらかの部分木にリスト状に値が格納されている
  ノード数nのとき、木の高さHは
   H = n
  なので
   O(n)

探索効率の良い二分探索木にするには
・左右の部分木をバランスさせ、 に近づける
 ・but... バランスした二分探索木を作るのは難しい
  ・ノードの でバランスが崩れるので、その都度再バランス化が必要
   →複雑なアルゴリズムを採用する必要がある
  ・バランスした二分探索木を作るアルゴリズム
   (例)
・あるいは、多分木を採用する
 ・これも実装はかなり複雑
   (例) …データベースのインデックスの実装などによく用いられる

実は、無理に平衡二分探索木を作らなくても...
・格納対象が大量のランダムデータであれば...
 ・ノード数nの二分探索木の高さは、高々 であることが知られている
 ※eはネイピア数(自然対数の底)
・この様なデータから作られる二分探索木
 ・木の高さは、完全な平衡二分探索木の高々 程度しか増えない(1.386倍)
 [このぐらいの効率低下は気にしなくていいよね] → 十分実用になる

二分探索木を作ろう!
作り方(もちろん再帰で作る)
ノードを追加する二分探索木が

 ・根となるノードを1つ作る
・空木でないとき
 ・追加する値が根の値より
   大きい→ へこの方法で追加
   小さい→ へこの方法で追加
   [再帰]
・データがなければ終了

指定した値を持つノードの削除
・注意…単純な削除はダメ!
 ・ノードの削除後も、二分探索木を保たなければならない

・順序木でない二分木のノード削除と同様に、3つ場合を考える
 ・リーフの場合
   …これは簡単、単純に削除しても二分探索木は保持される
 ・子を1つ持つノードの場合
   …これも簡単、単純に削除しても二分探索木は保持される
 ・子を2つ持つノードの場合
   …単純にリーフと置き換えてはダメ
  ・単純にリーフと置き換えると、二分探索木が
  ・置き換えの対象となる適切なノードを選ぶ
   ・適切なノードは、左部分木の または右部分木の
   ・これは必ず決まった場所にある
    ・左部分木の最大値→左部分木の のノード
    ・右部分木の最小値→右部分木の のノード
     [どちらを採用してもよいが通常は、前者を採用することが多い]

二分探索木内の値を全て取り出す(表示する)
・昇順(小さい順)に取り出す
 手順
 見ているノードが
 ・空木のとき
  ・何もしない
 ・空木でないとき
  ・ 部分木の値を、全てこの方法で取り出す
  ・根の値を取り出す
  ・ 部分木の値を、全てこの方法で取り出す
   [再帰]

探索方法…「

二分探索木内の値を全て取り出す(表示する)
・降順(大きい順)に取り出す
 手順
 見ているノードが
 ・空木のとき
  ・何もしない
 ・空木でないとき
  ・ 部分木の値を、全てこの方法で取り出す
  ・根の値を取り出す
  ・ 部分木の値を、全てこの方法で取り出す
   [再帰]