回 2-6 道 2 データ構造とアルゴリズム
二分探索木は、
読み終えたら片寄った
この頁の流れ
入れる
1,000 件を 入れた 木で、 なぜ 1,000 回も 見る ことがあるのか
二分探索木は、
前の
ただ、
そこで、
この
二分探索木は どんな 仕組みなのか
二分探索木は、
根、 葉、 親子、 高さという木の言葉
木は、
| 言葉 | 意味 |
|---|---|
| 根 (ルート) | いちばん上の節。 |
| 親と子 | 線で |
| 葉 | 子を |
| 部分木 | ある |
| 高さ | 根から |
二分木 (バイナリツリー) は、
この
探すときも 入れる ときも、 根から降りる
探す値を、
- いま見ている
節の 値と 同じなら、 見つかったので止まる - 探す値の
ほうが 小さければ 左の 子へ、 大きければ 右の 子へ降りる - 降りる
先が 無ければ、 その値は木に無い
入れる
このinsert は
探す
行きがけ、 通りがけ、 帰りがけのたどる順
木の
| 名前 | 出す順 | 主な |
|---|---|---|
| 行きがけ順 | 親、左、右 | 木を |
| 通りがけ順 | 左、親、右 | 小さい順に出す |
| 帰りがけ順 | 左、右、親 | 子を |
二分探索木を
この
並べた 配列の 二分探索と 何が違うのか
並べた
| 比べる所 | 並べた配列 | 二分探索木 |
|---|---|---|
| 探す | 真ん中を | 根から |
| 入れる | 後ろの | 空いた所に置くだけ |
| 消す | 後ろの | つなぎ直すだけ |
| 小さい順に出す | 前から読む | 通りがけ順でたどる |
| 形が崩れるか | 崩れない | 入れる |
Python のbisect.insort に
動かして確かめる
1 本目は、
動かす 木を作って、たどって、探す
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
行き 50 30 20 40 70 60 80
通り 20 30 40 50 60 70 80
帰り 20 40 30 60 80 70 50
高さ 3
50 (True, 1)
60 (True, 3)
20 (True, 3)
55 (False, 3)最初に
通りがけ順の
探した
二分探索木は どこで 崩れるのか
二分探索木は、
入れる 順で、 高さが 10 にも 1,000 にもなる
同じ
- 真ん中から
入れる。 全体の 真ん中の 値を 先に 入れ、 左右の 半分でも 同じ ことをくり返す - 混ぜて
入れる。 乱数の 代わりに 決まった 式で 混ぜた 順に 入れる (誰が 動かしても 同じになる) - 小さい
順に 入れる。 0、 1、 2 … 999 の順
出力は
動かす 入れる順で高さを測る
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
100 真ん中から 7 5.8
100 混ぜて 16 8.91
100 小さい順 100 50.5
1000 真ん中から 10 8.987
1000 混ぜて 22 12.336
1000 小さい順 1000 500.5真ん中から
混ぜて
小さい
図で
小さい 順に 入れる 場面は、 思ったより多い
会員番号や
並べた 配列と、 入れる 手間を比べる
1,000 個のbisect で
動かす 入れる手間を比べる
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
混ぜて
木で見た節 11336
配列でずらす 246632
小さい順
木で見た節 499500
配列でずらす 0混ぜた
小さい
普通の
片寄りを 直す木がある
片寄りを
Linux カーネルの
二分探索木は 仕事で どう 確かめるのか
仕事では、
- 通りがけ順で
出した 値が 小さい 順に 並んでいれば、 二分探索木の 決まりを 守っている。 下の コードのように 隣どうしを比べる - 高さを
測る。 件数 n に 対して 高さが n に 近いなら 片寄っている。上の depthsで最大と 平均を出す - 入れる
値の 順を 確かめる。 番号や 日時のように 増えていく 値を 鍵に するなら、 普通の 二分探索木は使わない - 言語の
道具を 使う。 Java なら 赤黒木の TreeMap、Python で値が めったに 増えないなら bisectで並べた リストで足りる
通りがけ順で決まりを確かめる
def is_bst(root):
out = ino(root, [])
ok = all(out[i] < out[i + 1]
for i in range(
len(out) - 1))
return ok関わる実例
Linux カーネルは、 赤黒木で 並んだ データを 持つ (2007年1月18日の文書)
Linux カーネルのrb_first と rb_next で
文書は
守られている
出典は Red-black Trees (rbtree) in Linux (The Linux Kernel documentation) です。
Java の TreeMap は、 赤黒木で log(n) を保証する
Java の java.util.TreeMap は、containsKey、get、put、remove に
会員番号のようにput しても、
よくある問い
二分探索木から 値を 消すには どうするのですか
消す節の
二分探索木は 配列で 表せますか
表せますが、
二分探索木の 計算量は、 平均と 最悪で どう 違いますか
探す、
AVL 木や 赤黒木は、 普通の 二分探索木と 何が 違いますか
どちらも
確認クイズ
答えだと
1 問目
このinsert はino は
通りがけ順で出す
root = None
for k in [8, 3, 10, 1, 6]:
root = insert(root, k)
print(*ino(root, []))2 問目
0 から
3 問目
1,000 個の
説明課題
同じ
自分の
この回の 先の一歩
データベースの
もっと深く
この
一次資料
どれも
- Red-black Trees (rbtree) in Linux (The Linux Kernel documentation、英語)。2007年1月18日の
日付、 自分で 釣り合いを 取る 二分探索木である こと、 回転の 最大の 回数、 AVL 木との比べ、 rb_firstとrb_next、Linux Weekly News を引いた使い道 - TreeMap (Java SE 21 API documentation、英語)。赤黒木を
もとに した 実装である こと、 4 つの 操作に log(n) を 保証する こと、 1.2 から 入ったこと - bisect, Array bisection algorithm (Python 公式文書、英語)。
insortではO(log n) で 探す手間が O(n) の 入れる 手間に 隠れること
次へ
道 2 データ構造とアルゴリズムの回
- 2-0アルゴリズムとは順次、
分岐、 反復の 3 つで書く手順頁で読む - 2-1線形探索と二分探索100 万件でも
20 回で見つかる頁で読む - 2-2バブルソートと
挿入・選択ソート遅い ソート 3 つ、 2 倍で 約 4 倍頁で読む - 2-3クイックソートと
マージソート速い ソート 2 つ、 平均と最悪頁で読む - 2-4スタックとキュー積む順と並ぶ順頁で読む
- 2-5再帰自分を
呼んで 小さくする頁で読む - 2-6木と
二分探索木たどる 順、片寄りこの回 - 2-7ハッシュテーブル鍵から
一気に 引く、衝突頁で読む - 2-8ダイクストラ法と最短経路点と
線、 幅優先、 重みのある道頁で読む - 2-9動的計画法同じ
計算を 2 度しない頁で読む - 2-10試験と
面接で確かめる基本情報 科目B、 道場 10 問、 面接 20 問頁で読む
