第8回:ツリー(1)二分探索木¶
前回まで:データを並べておけば、二分探索で速く引ける。でも 1 単語追加するたびに並べ直すのは O(n log n)。それを毎回やるのは現実的ではない。
今日の問い: 辞書を作りたい。単語を追加しながら、高速に検索したい。どう置けばいい?
演習8-1¶
届いた単語順に以下の手順で全部置く:
置けたら「cherry」と「fig」を探す。それぞれ何回比較したか記録する。
手順:
- 1つ目(grape)は真ん中に書く
- 2つ目からは、毎回いちばん上の単語からスタート
- 今いる単語と比べ、abc 順で前なら左下・後なら右下へ 1 段おりる
- おりた先に単語があれば 3 をくり返す
- おりた先が空なら、そこに書く
木構造¶
演習 8-1 で作ったような構造を「木」と呼ぶ。以降の説明では、次の小さな木を例に使う:
graph TD
5 --> 3
5 --> 8
3 --> 1
3 --> 4
8 --> 7
8 --> 9
- 探す側: 枝をたどるだけ。配列のように全部見る必要がない
- 追加する側: 空いた枝にぶら下げるだけ。配列の「ずらす」も連結リストの「先頭から全部見る」も起きない
木の言葉¶
- 根(root): 一番上の節(例:
5) - 節(node): 値 1 つ分のマス
- 葉(leaf): 子がいない節(例:
1,4,7,9) - 親 / 子: 線でつながった上が親、下が子
深さ・高さ・部分木¶
- 深さ(depth): 根から、その節までの線の本数(
rootは 0) - 高さ(height): 根から一番遠い葉までの線の本数(この木は 2)
- 部分木(subtree): ある節と、その下にぶら下がる全部
- 例:
3の下の1/4
- 例:
演習8-2¶
演習 8-1 の木に「kiwi」を追加してみよう。「kiwi」をたどるのに何回比較が必要?
二分探索木¶
ルール¶
どの節を見ても:
これだけ。さっき手で守っていたルールそのもの。
このルールがあるから「前なら左・後なら右」で候補を半分に切れる。
木を読むと、並びが出てくる¶
ある節では「左の子を全部 → 自分 → 右の子を全部」の順に読む。これを根から、どの部分木でも同じように再帰的に読み上げる(中順走査 / in-order traversal)。
- 二分探索木は、探すのが速いだけじゃない。整列された並びをいつでも取り出せる
- だから辞書に向く(速い検索+整った並び、両方)
二分探索 と 二分探索木¶
| 二分探索 | 二分探索木 | |
|---|---|---|
| 種類 | やり方(アルゴリズム) | 入れ物(データ構造) |
| 対象 | ソート済み配列 | 木そのもの |
| 半分に切る判断 | 真ん中の番号を計算 | 木の"形" そのもの |
| 追加のコスト | 配列=全部ずれて O(n) | 枝に掛けるだけで O(log n) |
同じ「半分に切る」発想。違いが出るのは追加。だから "木" が要る。
検索と追加¶
- 検索:
- 根から始める
- 小さければ左、大きければ右。一致で発見。行き止まり(空)なら無い
- 追加:
- 同じようにたどって、空いた枝先にぶら下げるだけ(誰もずらさない)
- 同じ単語が来たら何もしない(辞書なので重複させない)
計算量¶
- 比較の回数は、たどる線の本数 = 高さで頭打ち
- バランスのとれた木なら、高さ ≈ \(\log n\)
- 各段で節の数が倍に増える → n 個収めるのに約 \(\log_2 n\) 段で済む
- だから検索も追加も O(log n)
- 検索と追加は同じ道をたどる → コストも同じ
演習8-3¶
次の順番で届いた単語で木を作ろう。できた形をもとに「peach」を探し、何回比較したか数えよう。
演習8-4¶
演習 8-2 で完成させた木(kiwi を追加した状態)を根から「左の子を全部 → 自分 → 右の子を全部」の順で再帰的に読み上げ、出てきた単語を順に書け。
演習 8-1 / 8-2 のネタバレ注意:木の形を確認したい場合はここを開く
graph TD
grape --> banana
grape --> melon
banana --> apple
banana --> cherry
melon --> lemon
melon --> peach
lemon --> kiwi
演習8-5¶
次の 3 つの場面で、ソート済み配列 / 連結リスト / 二分探索木 のどれが最適? 理由も一言。
- (a) 一度作ったら変わらないデータを、ひたすら検索だけする
- (b) データが来た順に末尾へ足すだけ。検索はしない
- (c) 単語を足しながら、何度も検索する
まとめ¶
- 木の言葉: 根・節・葉・親子/深さ・高さ・部分木
- 二分探索木: 左 < 自分 < 右。検索も追加もたどる線 = 高さ分(バランス時 O(log n))。偏ると O(n)
- 左 → 自分 → 右で読むと整列が出てくる = 整った辞書そのもの
- 「半分にする」が、探索 → 並べ替え → 木 と一貫して効いてきた
次回予告¶
今日まで:二分探索木なら、検索も追加も速い(バランス時 O(log n))。でも、入れる順が悪いと木が偏り、O(n) に逆戻りすることがある。
「どんな順で入れても、勝手に整って速さを保つ」木があれば……。
次回:ツリー(2)平衡二分探索木。順番に振り回されない木は、どう作る?