講義「アルゴリズムとデータ構造」
第6回 探索のためのデータ構造(1)
大学院情報科学研究院 情報理工学部門 情報知識ネットワーク研究室
喜田拓也
2019/5/22 講義資料
今日の内容
探索
※
のためのデータ構造整列済み配列による辞書の実現 二分探索木による辞書の実現 平衡探索木による辞書の実現
※
探索: データの中から,特定の要素を探し出すこと2
探索のためのデータ構造: 辞書 (dictionary)
次の3つの基本操作を伴う集合
𝑆𝑆
を辞書(dictionary
)という1. member( 𝑥𝑥 , 𝑆𝑆 ): 𝑥𝑥 ∈ 𝑆𝑆
ならばyes, 𝑥𝑥 ∉ 𝑆𝑆
ならばno
を出力2. insert( 𝑥𝑥 , 𝑆𝑆 ): 𝑆𝑆
を𝑆𝑆 ∪ 𝑥𝑥
に更新3. delete( 𝑥𝑥 , 𝑆𝑆 ): 𝑆𝑆
を𝑆𝑆 − 𝑥𝑥
に更新調べたり 新しい項目を書き入れたり 項目を消したり(汗
3
整列済み配列による辞書の実現
以降,集合
𝑆𝑆
は全順序集合であると仮定する 配列𝐴𝐴
に𝑆𝑆
の要素を小さい順に格納するmember( 𝑥𝑥, 𝑆𝑆 )
: 配列上を二分探索するinsert( 𝑥𝑥, 𝑆𝑆 )
:𝑥𝑥
が入る位置を見つけたら,それ以降の要素を後ろにずらして,できた空 きに
𝑥𝑥
を入れるdelete( 𝑥𝑥, 𝑆𝑆 )
:𝑥𝑥
の位置を見つけたら,それ 以降の要素を一つずつ前に詰めていく.𝑆𝑆
の 最後の要素は空きとなるdelete( 7, 𝑆𝑆 )
の処理1 3 5 7 9 10 12
最悪時間計算量
O log 𝑛𝑛
次で説明O 𝑛𝑛
O 𝑛𝑛
1 3 5 9 9 10 12 1 3 5 9 10 10 12 1 3 5 9 10 12 12 1 3 5 9 10 12
𝑆𝑆
コピー
削除
𝐴𝐴
は整列(ソート)済み配列4
配列を二分探索するアルゴリズム
Step 1: left ← 0 , right ← 𝑛𝑛
Step 2: left ≥ right
ならno
を出力して停止Step 3: mid ← ⌊ (left + right)/ 2⌋
Step 4: if 𝑥𝑥 < 𝐴𝐴 [mid]
then right ← mid
else if 𝑥𝑥 = 𝐴𝐴 [mid]
then yes
を出力して停止else left ← mid +1
Step 2
へ1回で範囲を半分以下に絞れるので,
𝑘𝑘
回で範囲を𝑛𝑛/2
𝑘𝑘以下に絞れる 範囲が空となったら終わりだから𝑛𝑛/2
𝑘𝑘< 1
.よってlog
2𝑛𝑛 < 𝑘𝑘
.これを満たす最小の整数
𝑘𝑘
は⌊ log
2𝑛𝑛 + 1⌋
このループは高々
⌊ log
2𝑛𝑛 + 1⌋
回member( 5, 𝑆𝑆 )
の場合1 3 5 7 9 10 12
𝑆𝑆
left mid right
1 3 5 7 9 10 12 0 1 2 3 4 5 6 7
1 3 5 7 9 10 12
yes
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7
5
二分探索木による辞書の実現
二分木(
binary tree
)とは,各節点が高々二つの子をもつ根付き木二分探索木(
binary search tree
)とは,任意の節点𝑢𝑢
に対して次の 条件が成り立つ二分木のこと2
分木の例2
分探索木の例根
𝑢𝑢 𝑢𝑢
の子𝑣𝑣
𝑣𝑣
の親7
3 10
1 4
5
8 6
𝑢𝑢
𝑢𝑢
の左部分木
𝑢𝑢
の右部分木
5
3 7
1 4
8 6 10
同じ要素が格納された 異なる二分探索木
𝑢𝑢
の左部分木の任意の節点の要素 <
𝑢𝑢
の要素 <𝑢𝑢
の右部分木の任意 の節点の要素子が1個の場合もある
この二分探索木を使って全順序集合
𝑆𝑆
を管理し,辞書とする6
二分探索木における member( 𝑥𝑥, 𝑆𝑆 ) 操作
Step 1: 𝑢𝑢 ←
根の節点Step 2: 𝑦𝑦 ←
節点𝑢𝑢
の要素Step 3: if 𝑥𝑥 = 𝑦𝑦 then
yes
を出力して停止else if 𝑥𝑥 > 𝑦𝑦 then
if 𝑢𝑢
の右の子が存在then
𝑢𝑢 ← 𝑢𝑢
の右の子else
no
を出力して停止else if 𝑢𝑢
の左の子が存在then
𝑢𝑢 ← 𝑢𝑢
の左の子else
no
を出力して停止Step 2
へmember( 5, 𝑆𝑆 )
の場合7
3 10
1 4
5
8 6
yes
5 <
< 5
< 5 5 <
5 =
𝑢𝑢
𝑥𝑥 ≤ 𝑦𝑦
member( 9, 𝑆𝑆 )
の場合7
3 10
1 4
5
8 6
𝑢𝑢
< 99 <
< 9
no
7
二分探索木における insert (𝑥𝑥 , 𝑆𝑆) 操作
Step 1: 𝑢𝑢 ←
根の節点Step 2: 𝑦𝑦 ←
節点𝑢𝑢
の要素Step 3: if 𝑥𝑥 = 𝑦𝑦 then
何もしないで停止else if 𝑥𝑥 > 𝑦𝑦 then
if 𝑢𝑢
の右の子が存在then
𝑢𝑢 ← 𝑢𝑢
の右の子else
𝑢𝑢
の右の子として𝑥𝑥
を要素とする 節点を追加して停止else if 𝑢𝑢
の左の子が存在then
𝑢𝑢 ← 𝑢𝑢
の左の子else
𝑢𝑢
の左の子として𝑥𝑥
を要素とする 節点を追加して停止Step 2
へinsert( 9, 𝑆𝑆 )
の場合赤字の部分が
member( 𝑥𝑥, 𝑆𝑆 )
操作と違うところ7
3 10
1 4
5
8 6
𝑢𝑢
< 99 <
< 9 9 追加
8
二分探索木における delete( 𝑥𝑥, 𝑆𝑆 ) 操作
Step 1: 𝑢𝑢 ←
根の節点Step 2: 𝑦𝑦 ←
節点𝑢𝑢
の要素Step 3: if 𝑥𝑥 = 𝑦𝑦 then Step 4
へelse if 𝑥𝑥 > 𝑦𝑦 then
if
右の子が存在then 𝑢𝑢 ←
右の節点else
何もしないで停止else if
左の子が存在then 𝑢𝑢 ←
左の節点else
何もしないで停止Step 2
へStep 4: if 𝑢𝑢
は葉then 𝑢𝑢
を木から除いて停止else if 𝑢𝑢
が1つの子をもつthen 𝑢𝑢
の子を𝑢𝑢
の位置に上げて停止else 𝑣𝑣 ← 𝑢𝑢
の右部分木の最小要素をもつ節点Step 5: 𝑢𝑢
の要素← 𝑣𝑣
の要素Step 6: if 𝑣𝑣
は葉then 𝑣𝑣
を木から除いて停止else ( 𝑣𝑣
が1つの子を持つ場合)
𝑣𝑣
を𝑢𝑢
の位置に上げて停止𝑣𝑣
は部分木の最小要素をもつ節点なので 子の数は高々1つ
これ以降は
𝑢𝑢
が2つ の子をもつ場合𝑆𝑆
中に𝑥𝑥
が無ければ 何もしない9
二分探索木における delete( 𝑥𝑥, 𝑆𝑆 ) 操作の例
7
3 10
1 4
5
8 6 5 <
< 5
< 5 5 <
5 =
𝑢𝑢
delete( 5, 𝑆𝑆 )
の場合7
3 10
1 4
5
8 6 4 <
< 4
= 4
𝑢𝑢
delete( 4, 𝑆𝑆 )
の場合7
3 10
1 4
5
8 6
7
3 10
1 5
8 6
7
3 10
1 4
5
8 6 7 =
delete( 7, 𝑆𝑆 )
の場合𝑢𝑢
𝑣𝑣
8
3 10
1 4
5
8 6
7
3 10
1 4
5
8 6 3 <
= 3
𝑢𝑢
delete( 3, 𝑆𝑆 )
の場合𝑣𝑣
7
4 10
1 5
6 8
10
二分探索木に対する操作の時間計算量
𝑛𝑛
要素の二分探索木に対する各操作の計算時間は,𝑥𝑥 ∈ 𝑆𝑆
の場合,𝑥𝑥
を要素としてもつ節点の深さ※に比例する𝑥𝑥 ∉ 𝑆𝑆
の場合,insert( 𝑥𝑥, 𝑆𝑆 )
を行うことによってできる𝑥𝑥
を 要素としてもつ節点の深さ−1
に比例する最悪時間計算量は
O(𝑛𝑛)
,平均時間計算量はO log 𝑛𝑛
大きい順に格納
※𝑥𝑥 が2つの子を持つ場合のdelete(𝑥𝑥,𝑆𝑆)は,𝑥𝑥 の右部分木の最小要素の節点𝑣𝑣 の深さにも比例
4 3 2 1
最悪な場合(木の深さ
= 𝑛𝑛 − 1
) 最良の場合(木の深さ= log 𝑛𝑛
)4 3 2 1
小さい順に格納
5
5
5 4
2
1 3
6
6 6
節点の深さの期待値は
O log 𝑛𝑛
11
深さの期待値が O log 𝑛𝑛 である証明
(証明) 二分探索木の全ての節点がちょうど2つの子をもつように
𝑛𝑛 + 1
個の節点を加える.もとの節点を内点,新しく加えた節点を外点と呼ぶ.
「外点の深さの平均」
≥
「内点の深さの平均」であるから外点の深さの平均が
O log 𝑛𝑛
であることを示せばよい.7
3 10
1 4
5
8 6
内点
外点
トーナメントの 試合数を考え てみよう
0 1 2 3 4 5
節点の深さ=
根からの路の長さ
12
証明つづき
𝐷𝐷 𝑛𝑛
を外点の深さの平均とする.最初に格納されるものが
𝑖𝑖
番目の大きさで ある確率を1/𝑛𝑛
(等確率)とすれば,𝐷𝐷 𝑛𝑛 = 1 𝑛𝑛 �
𝑖𝑖=1𝑛𝑛
𝑖𝑖 𝐷𝐷 𝑖𝑖 − 1 + 1 + (𝑛𝑛 − 𝑖𝑖 + 1)(𝐷𝐷 𝑛𝑛 − 𝑖𝑖 + 1) 𝑛𝑛 + 1
= 2
𝑛𝑛 𝑛𝑛 + 1 �
𝑖𝑖=1 𝑛𝑛
𝑖𝑖𝐷𝐷(𝑖𝑖 − 1) + 1
= 2
𝑛𝑛 𝑛𝑛 + 1
2
𝑛𝑛 𝑛𝑛 − 1 �
𝑖𝑖=1 𝑛𝑛−1
𝑖𝑖𝐷𝐷 𝑖𝑖 − 1 + 1 𝑛𝑛 𝑛𝑛 − 1
2 − 𝑛𝑛 𝑛𝑛 − 1
2 + 𝑛𝑛𝐷𝐷 𝑛𝑛 − 1 + 1
= 𝐷𝐷 𝑛𝑛 − 1 + 2 𝑛𝑛 + 1
外点の数
=
内点の数+1𝐷𝐷(𝑛𝑛 − 1)
内点が
𝑖𝑖 − 1
個内点が
𝑛𝑛 − 𝑖𝑖
個 根の要素の大きさが𝑖𝑖
番目𝐷𝐷 𝑖𝑖 − 1
左側の総深さ 右側の総深さ𝑖𝑖𝐷𝐷 𝑖𝑖 − 1
と𝑛𝑛 − 𝑖𝑖 + 1 𝐷𝐷(𝑛𝑛 − 𝑖𝑖)
は𝑖𝑖
に対して対称なので𝑖𝑖 = 𝑛𝑛
のところを抽出して分解13
証明つづき
よって,
𝐷𝐷(𝑛𝑛) − 𝐷𝐷(𝑛𝑛 − 1) = 2/(𝑛𝑛 + 1)
となる.𝐷𝐷 0 = 0
であるから,𝐷𝐷 𝑛𝑛 = 2 �
𝑖𝑖=2 𝑛𝑛+1 1
𝑖𝑖 ≤ 2 �
1
𝑛𝑛+1 1
𝑥𝑥 𝑑𝑑𝑥𝑥 = 2 log 𝑒𝑒 (𝑛𝑛 + 1)
したがって𝐷𝐷 𝑛𝑛 = O log 𝑛𝑛
である. 【証明終わり】調和級数の部分和
…
1/2 1
1/3
1 2 𝑛𝑛 𝑛𝑛 + 1
𝑦𝑦 = 1 𝑥𝑥 𝑦𝑦
𝑥𝑥
14平衡探索木( balanced search tree )
各節点において,その子を根とする全ての部分木の高さがほぼ 平衡している探索木
AVL
木 どの節点においても,その左部分木と右部分木の高さ の差が1以下である二分探索木AVL
は提唱者(Adel’son-Vel’skii
とLandis
)の頭文字2
色木 二分探索木の各辺に次の条件を満たすように赤か黒の色を塗れるもの
1.
外点に接続する辺の色は黒2.
根から外点までのどの路も赤い辺が連続しない3.
根から外点までのどの路も含む黒い辺の数が同じB
木 根と葉を除く各節点が𝑚𝑚/2
個以上,𝑚𝑚
個以下の子を持つ探索木(
𝑚𝑚
は自然数)2-3
木𝑚𝑚 = 3
の場合のB
木1 ≥
15
AVL 木における insert( 𝑥𝑥, 𝑆𝑆 ) 操作
𝑇𝑇 𝐿𝐿 𝑢𝑢
を節点𝑢𝑢
の左部分木,𝑇𝑇 𝑅𝑅 𝑢𝑢
を𝑢𝑢
の右部分木,𝑠𝑠(𝑢𝑢)
を𝑢𝑢
の状態とする挿入前の
𝑠𝑠(𝑢𝑢)
は次のように設定されている.𝑆𝑆 𝑢𝑢 = � 𝐿𝐿, 𝑇𝑇 𝐿𝐿 𝑢𝑢
の高さ> 𝑇𝑇 𝑅𝑅 𝑢𝑢
の高さの場合,𝐸𝐸, 𝑇𝑇 𝐿𝐿 𝑢𝑢
の高さ= 𝑇𝑇 𝑅𝑅 𝑢𝑢
の高さの場合,𝑅𝑅, 𝑇𝑇 𝐿𝐿 𝑢𝑢
の高さ< 𝑇𝑇 𝑅𝑅 𝑢𝑢
の高さの場合.Step 1:
二分木と同様に挿入を行う.挿入した節点の親を𝑢𝑢
とするStep 2: 𝑠𝑠 𝑢𝑢 ≠ 𝐸𝐸
となるまで次のことを繰り返す1. 𝑠𝑠 𝑢𝑢
を,挿入して高くなった方(𝐿𝐿
か𝑅𝑅
)に更新2. 𝑢𝑢 ← 𝑢𝑢
の親Step 3: if 𝑠𝑠 𝑢𝑢 = 𝑅𝑅
かつ𝑇𝑇
𝐿𝐿𝑢𝑢 が高くなったor 𝑠𝑠 𝑢𝑢 = 𝐿𝐿
かつ𝑇𝑇
𝑅𝑅𝑢𝑢 が高くなったthen
𝑠𝑠 𝑢𝑢 ← 𝐸𝐸
として停止else
回転して停止左が高い
右が高い
挿入したこと による祖先の ラベル変更
ここの処理は 定数時間
16
AVL 木における挿入(左)に伴う回転操作
𝑢𝑢 𝑣𝑣
𝐸𝐸 ⇒ 𝐿𝐿
𝐿𝐿 𝑢𝑢
𝑣𝑣 𝐸𝐸
𝐸𝐸
回転11
1
回転
1
𝑢𝑢
𝑤𝑤
𝐸𝐸 ⇒ 𝐿𝐿 𝑅𝑅 𝑣𝑣
𝐿𝐿 𝑢𝑢
𝑤𝑤 𝐸𝐸
𝐸𝐸 𝑣𝑣 𝑅𝑅
𝑠𝑠 𝑣𝑣 = 𝐿𝐿
の場合𝑠𝑠 𝑣𝑣 = 𝑅𝑅
の場合𝑇𝑇
𝐿𝐿𝑤𝑤< 𝑇𝑇
𝑅𝑅𝑤𝑤 の場合もある 17AVL 木における delete( 𝑥𝑥, 𝑆𝑆 ) 操作
Step 1:
一般の二分木の同じように削除を行う.削除した最も下の節点の親を
𝑢𝑢
とする.Step 2: 𝑠𝑠 𝑢𝑢 = 𝐸𝐸
となるまで次のことを繰り返す.1. if 𝑠𝑠 𝑢𝑢 = 𝐿𝐿
かつ𝑇𝑇
𝐿𝐿𝑢𝑢 が低くなったor 𝑠𝑠 𝑢𝑢 = 𝑅𝑅
かつ𝑇𝑇
𝑅𝑅𝑢𝑢 が低くなったthen 𝑠𝑠(𝑢𝑢) ← 𝐸𝐸
else if 𝑠𝑠 𝑢𝑢 = 𝑅𝑅
かつ𝑇𝑇
𝐿𝐿𝑢𝑢 が低くなったor 𝑠𝑠 𝑢𝑢 = 𝐿𝐿
かつ𝑇𝑇
𝑅𝑅𝑢𝑢 が低くなったthen (1)
回転(2) 𝑠𝑠 𝑢𝑢 ≠ 𝐸𝐸
ならば停止2. 𝑢𝑢 ← 𝑢𝑢
の親Step 3: 𝑠𝑠 𝑢𝑢
を,低くなった方の逆(𝐿𝐿 or 𝑅𝑅
)に更新高々,木の高 さの回数しか 繰り返さない 回転処理は
定数時間
18
11 11
AVL 木における削除(左)に伴う回転操作
𝑣𝑣 𝑢𝑢 𝑅𝑅
𝐸𝐸
𝑣𝑣
𝑅𝑅 𝑢𝑢
𝐿𝐿
高さ変化せず
𝑣𝑣 𝑢𝑢 𝑅𝑅
𝑅𝑅
𝑣𝑣
𝐸𝐸 𝑢𝑢
𝐸𝐸
高さ
1
減少回転
回転
𝑠𝑠 𝑣𝑣 = 𝐸𝐸
の場合𝑠𝑠 𝑣𝑣 = 𝑅𝑅
の場合19
AVL 木における削除(左)に伴う回転操作
高さ1減少
𝑠𝑠 𝑣𝑣 = 𝐿𝐿
の場合𝑢𝑢
𝑤𝑤
𝑅𝑅 𝐿𝐿 𝐸𝐸 𝑣𝑣
11
𝑢𝑢
𝑤𝑤 𝐸𝐸
𝐸𝐸 𝐸𝐸 𝑣𝑣
回転
20
AVL 木に対する操作の時間計算量
𝑛𝑛
要素のAVL
木に対する各操作の計算時間は,最悪時間計算量は
O(log 𝑛𝑛)
,平均時間計算量はO log 𝑛𝑛
AVL
木のどの操作も,木の高さに比例した時間しかかからない.𝑛𝑛
節点のAVL
木の高さはO log 𝑛𝑛
21
AVL 木の高さが O log 𝑛𝑛 の証明
𝑓𝑓 ℎ
を高さℎ
のAVL
木の最小節点数とすれば,以下の漸化式 が成り立つ.𝑓𝑓(ℎ) = 𝑓𝑓(ℎ − 1) + 𝑓𝑓(ℎ − 2) + 1
,𝑓𝑓(0) = 1
,𝑓𝑓(1) = 2
.𝐹𝐹 ℎ = 𝑓𝑓 ℎ + 1
とすれば,𝐹𝐹 ℎ = 𝐹𝐹 ℎ − 1 + 𝐹𝐹 ℎ − 2
,𝐹𝐹 (0) = 2
,𝐹𝐹 (1) = 3
. すると,𝐹𝐹 ℎ
はフィボナッチ数列なので,𝐹𝐹(ℎ) = 𝜑𝜑 1 ℎ+3 − 𝜑𝜑 2 ℎ+3 5
ただし,
𝜑𝜑 1 = 1+ 5 2
,𝜑𝜑 2 = 1− 5 2
である.高さ
ℎ
の節点数最小のAVL
木高さ
ℎ − 1
の 節点数最小 のAVL
木 高さℎ − 2
の節点数最小 の
AVL
木根だけの木
22
証明つづき
高さ
ℎ
のAVL
木の節点数を𝑛𝑛
とすれば,𝑓𝑓 (ℎ)
はその下限なので,𝑓𝑓 ℎ ≤ 𝑛𝑛
である.よって,𝜑𝜑 1 ℎ+3 − 𝜑𝜑 2 ℎ+3 ≤ 5 𝑛𝑛 + 1
.𝜑𝜑 2 < 1
なので,𝜑𝜑 1 ℎ+3 − 1 ≤ 5 𝑛𝑛 + 1
. よって,ℎ ≤ log 5 𝑛𝑛 + 1 + 1
log 𝜑𝜑 1 − 3
.したがって,
ℎ = 𝑂𝑂 log 𝑛𝑛
である. 【証明終わり】∵ 𝜑𝜑
1ℎ+3− 𝜑𝜑
2ℎ+35 = 𝑓𝑓 ℎ + 1
23
今日のまとめ
探索のためのデータ構造である辞書の実現方法を学んだ 整列済み配列による辞書の実現
member
は最悪時間計算量O(log 𝑛𝑛) insert
とdelete
はO(𝑛𝑛)
かかる二分探索木による辞書の実現 最悪時間計算量
O 𝑛𝑛
平均時間計算量
O log 𝑛𝑛
平衡探索木による辞書の実現最悪時計算量も平均時間計算量も
O log 𝑛𝑛
24