2015/12/02 1
アルゴリズムとデータ構造
第 7 回:探索のためのデータ構造( 3 )
前半:最適 2 分探索木の構築(発展)
後半:ハッシュ表(基本)
第 7 回 探索のためのデータ構造( 2 )
n
今日の内容:¨
今日は短い内容が二つあります。¨
前半: (発展内容)最適2
分探索木を学ぼう。n 「発展内容」なので、わからないときは飛ばしても良いです。(試験にでません)
n これは、検索のみで挿入と削除をしないときに、平衡二分探索木(第6回)よりも検索時間が 短くなるデータ構造を見つける話です。表を埋めることで、計算を高速に行う「動的計画法」の 例です。興味ある人はどうぞ!
¨
後半:(基本内容)「ハッシュ表」を学ぼう。n ハッシュ表は、平均的にO(1)時間で探索できる、実用的に効率が良い探索データ構造です。
n
ポイント¨
前半:最適2
分探索木の計算は、本当はけっこう難しいが(全部候補の木を探すと指数 時間かかる)、表を埋めていくことで、高速に計算できる。¨
後半:「ハッシュ表」では、「ハッシュ関数」を用いて検索する方法を理解しよう。¨
後半: ハッシュ表には、衝突回避法の違いで、「外部ハッシュ法」と「内部ハッシュ法」があ ります。「内部ハッシュ法」は、簡単な仕組みで手品のようにうまく、衝突を回避できます。¨ C++
のunordered_map
や、java
のHashMap
は、ハッシュ表で実装されています。アルゴリズムとデータ構造
2
2015/12/02 3
アルゴリズムとデータ構 造
第 7 回前半:探索のためのデータ構造( 3 )
前半: 最適 2 分探索木の構築(発展)
アルゴリズムとデータ構造
2015 2015/12/02
4 前回の復習
辞書に適したデータ構造とは?
次の3つの基本操作を伴う集合
S
を辞書(dictionary)
という。1. member(x,S) : x∈S
ならばyes, x S
ならばno
を出力2. Insert(x,S) : SをS∪{x}に更新
3. delete(x,S) : S
をS
-{x}
に更新∈
要するに検索と 挿入と削除が 高速に行える
データ構造
1.整列された配列
member
最悪時間計算量O(log n)
insert, deleate
最悪時間計算量O(n)
これは問題!2.2分探索木
member,insert,delete
最悪時間計算量O(n)
平均時間計算量
O(log n)
挿入の順番がランダム 3.平衡2分探索木 と仮定AVL
木(全ての節点において、左部分木と右部分木の高さの差が1以内の2分探索木)member,insert,delete
最悪時間計算量O(log n)
5 本日の内容
Q
1.平衡2分探索木よりもっと良い2分探索木はあるのか?↓
検索のみの高速化なら可能!
検索される要素の確率分布が分かっているときに、その確率分布に対して,
検索にかかる時間が平均的に最も少なくなるような木を構築することが可能
↑
最適2分探索木
Q2.
検索・挿入・削除の時間計算量は、O(log n)
の壁を破れないか?平均時間計算量なら可能!
ハッシュ表を用いれば、平均時間計算量を
O(1)
(定数時間)で行える。ただし、ハッシュ表のサイズ
m
を格納要素数n
のオーダーO(n)
にとった場合にO(1)を実現可能
ハッシュ表は最も実用的な辞書に適した構造
最適 2 分探索木の構築問題
n
入力:¨ n
個のデータ値a 1 < a 2 <…< a n
(実数値)¨
データ値の出現確率の表P
(右図)n
タスク:¨ n
個のデータ値を格納するすべての二分探索木の中か ら,表の出現確率に関して平均探索コストが最小とな る2
分決定木T
(最適2
分探索木)を求めよアルゴリズムとデータ構造 有村博紀
6
補足スライド値の生成確率の表
P
(-∞,a1) 0.050
a1 0.050
(a1,a2) 0.050
a2 0.025
(a2,a3) 0.050
a3 0.125
(a3,a4) 0.050
a4 0.250
(a4,a5) 0.050
a5 0.075
(a5,a6) 0.050
a6 0.125
(a6,+∞) 0.050 1.000
n
補足¨
平均探索時間は,
値X
を格納する頂点深さcost(X)
としてCost(T) := Σ X:値または区間 P(X) cost(X)
¨
素朴な方法は,S
を格納するすべての可能な二分探索木を すべてに対する総当たり.n 要素は昇順にソートされているとして良く,木の形だけ.
n 要素数がnのすべての可能な2分探索木の総数
= n
nくらい¨
もっと効率よく解けないか?=> 「動的計画法」
プログラミングコンテス トの問題風に*
*) 過去のプログラミングコンテストによく出題されている(例:KUPC2012)
a
4a
3a
6a
1a
2a
5v
0v
1v
2v
3v
4v
5v
6基本的アイディア
n
ソートしたn
個のデータ値a 1 < a 2 <…< a n
仮定を格納した 長さn
の配列A
を考えるn
一つの部分木は,配列の部分区間A[i..j]
に対する最適 部分木を求めれば良い.n 2
分探索木は,真ん中の要素A[k]
を選べば根が決まるn A[i..j]
は,真ん中の要素A[k]
と 二つの部分A[i..k-1]
とA[k+1..j]
に分割できる.n
それぞれの最適木を求めれば良い?n
表にして求める.n
何個のマス目が必要?7
a
kT i,k-1 T k+1,j
アルゴリズムとデータ構造
2015 2015/12/02
8
最適 2 分探索木の定義 (1/2)
S={a 1 , a 2 ,…,a n } :
格納要素。ただしa 1 <a 2 <
・・・<a n
とする。次の確率
(a 1 ,...,a n ), (β 0 ,...,β n )
が与えられていると仮定。P{x=a i }=α i (i=1,2,…,n)
P{x<a 1 }=β 0 , P{a i <x<a i+1 }=β i (i=1,2,…,n-1), P{a n <x}=β n T :S
を節点要素としてもつ2分探索木T
の各節点がちょうど2つの子をもつようにn+1
個の架空の点(外点)を導入。節点
a i :
要素a i
が割り当てられている節点外点
v 0 :x<a 1
のときにmember(x,S)
により(仮想的に)たどり着く外点外点
v i (i=1,2,…,n-1): a i <x<a i+1
のときにmember(x,S)
によりたどり着く外点 外点v n :x>a n
のときにmember(x,S)
によりたどり着く外点a
4a
3a
6a
1a
2a
5v
0v
1v
2v
3v
4v
5v
69
最適 2 分探索木の定義 (2/2)
S⊆X:
全順序集合最適2分探索木
(optimal binary search tree)
とは 検索コスト(member(x,S)
の平均時間計算量)
が最小の2分探索木
最適2分探索木は次式で定義されるコスト
c
を最小化する2分探索木T
である。c(T)=Σα i (depth T (a i )+1)+Σβ i depth T (v i )
ただし、
depth T (u)
は2分探索木T
における節点u
の深さを表すものとする。i=1
n n
i=0 ←
平均比較回数a
4a
3a
6a
1a
2a
5v
0v
1v
2v
3v
4v
5v
6アルゴリズムとデータ構造
2015 2015/12/02
10
最適2分探索木の構成法
T i,j :
節点a i , a i+1 ,…,a j
からなる2分探索木T i,j
のコストを同様に次のように定義する。c(T i,j )=Σα p (depth Ti,j (a p )+1)+Σβ p depth Ti,j (v p )
木
T i,j
は根が節点a k
であれば、ある木T i,k-1
と木T k+1,j
を用いて、左図のように表現できる。c i,j =min Ti,j c(T i,j )
と定義する。最終的には
c(T)=c 1,n
となるような木T
を求めればよい。c i,j =min min min ( c(T i,k-1 )+Σ α p + Σ β p + α k + c(T k+1,j ) + Σ α p + Σ β p )
p=i
j j
p=i-1
a
kT i,k-1 T k+1,j
k:i≦k≦j T
i,k-1T
k+1,jp=i p=i-1 p=k+1 p=k
k-1 k-1 j j
P{a i-1 <x<a k } P{a k <x<a j+1 }
=min (c i,k-1 + c k+1,j ) + Σα p + Σβ p
k:i≦k≦j p=i
j
p=i-1 j
よって最適な木
T i,j
のコストc i,j
はより小さな最適な木T i,k-1 , T k+1,j (i ≦ k ≦ j)
のコスト
c i,k-1 , c k+1,j
から求めることができる。11
最適2分探索木の構成法 (
続き)
c i,j =min (c i,k-1 + c k+1,j ) + Σα p + Σβ p
k:i≦k≦j p=i
j
p=i-1 j
T i,i-1
はa i-1 <x<a i
に対する木であり外点v i-1
のみからなる木である。コストの定義よりc
i,i-1 =c(T i,i-1 )=0となる。
したがって、まとめると以下の漸化式が得られる。
c i,i-1 =0
for 1≦i≦j≦n for 1≦i≦n
この漸化式より、
c 1,n
およびそのコストを達成する最適2分探索木T
を 動的計画法を使って時間計算量O(n 2 )
で計算可能。動的計画法とは
対象となる問題の部分問題の解を計算して記憶しておき、
それらを用いて元の問題の解を計算する技法
上記漸化式の場合、
c i,j
の値の計算には、j’-i’<j-i
であるc i’,j’
しか使わない。したがって、j-i
の値が小さなc i,j
から順に計算すれば各c i,j
をO(j-i+1)
で求めることができる。アルゴリズムとデータ構造
2015 2015/12/02
12
例
S={a 1 ,a 2 ,a 3 ,a 4 ,a 5 }
α 1 =α 2 =α 3 =0.1, α 4 =α 5 =0.2, β 0 =β 1 =β 3 =β 4 =β 5 =0.05
の場合0
0
0
0
0
0 c i,j
の値k=1 0.2
k=2 0.2
k=3 0.2
k=4 0.3
k=5 0.3
k=1 0.55
k=2 0.55
k=4 0.85
k=2 0.9
k=4 1.2
k=2 1.6
k=4 1.7 k=4 1 2.2
2 3 4 5 6 i
0 1 2 3 4 5 j
-1 0
1 2
3 4 j-i
k=3 1.1 k=4 0.65
c 2,4 = min {c 2,1 +c 3,4 , c 2,2 +c 4,4 , c 2,3 +c 5,4 } + (α 2 +α 3 +α 4 ) + (β 1 +β 2 +β 3 +β 4 )
= min {0.65, 0.5, 0.55}
+ 0.4 + 0.2
= 1.1
(
最小はc 2,2 +c 4,4
でk=3
のとき)a
4a
2a
5a
1a
3最適2分探索木は
13
最悪時間計算量は O(n 2 )
j-i=h
の場合、n-h
個のc i,j
を計算しなければならない。1つの
c i,j
を求めるのにh+1
個の候補から最小値を計算するので、全体ではO(Σ(n-h)(h+1))=O(n 3 )
となるが、最小候補をもっと絞り込むことができるため工夫をすれば
O(n 2 )
の最悪時間計算量で計算可能である。c i,j
を最小にする候補の木T i,j
の根節点a k
は、i≦k≦j
よりさらに絞り込めてr i,j-1 ≦k≦r i+1,j
であることが知られている。ただし、r i,j
は最適な木T i,j
の根節点のインデックス、つまり
a m
を最適な木T i,j
の根節点とするとr i,j =m
である。この事実を使うと上の計算は以下のようになる。
h=0 n-1
O (r i+ 1,i+h − r i,i+h−1 + 1)
i=1 n−h
∑
h=0 n−1
# ∑
$ % &
' ( = O (r n−h+ 1,n − r 1,h + n − h
h=0 n− 1
∑ )
#
$ % &
' ( = O(n 2 )
2015/12/02
アルゴリズムとデータ構造2015 14
アルゴリズムとデータ構 造
第 7 回:探索のためのデータ構造( 3 )
後半:ハッシュ表
15 前回の復習
辞書に適したデータ構造とは?
次の3つの基本操作を伴う集合
S
を辞書(dictionary)
という。1. member(x,S) : x∈S
ならばyes, x S
ならばno
を出力2. Insert(x,S) : SをS∪{x}に更新
3. delete(x,S) : S
をS
-{x}
に更新∈
要するに検索と 挿入と削除が 高速に行える
データ構造
1.整列された配列
member
最悪時間計算量O(log n)
insert, deleate
最悪時間計算量O(n)
これは問題!2.2分探索木
member,insert,delete
最悪時間計算量O(n)
平均時間計算量
O(log n)
挿入の順番がランダム 3.平衡2分探索木 と仮定AVL
木(全ての節点において、左部分木と右部分木の高さの差が1以内の2分探索木)member,insert,delete
最悪時間計算量O(log n)
アルゴリズムとデータ構造
2015 2015/12/02
16 本日の内容
Q2.
検索・挿入・削除の時間計算量は、O(log n)の壁を破れないか?平均時間計算量なら可能!
ハッシュ表を用いれば、平均時間計算量を
O(1)
(定数時間)で行える。ただし、ハッシュ表のサイズmを格納要素数nのオーダーO(n)にとった場合に
O(1)
を実現可能ハッシュ表は最も実用的な辞書に適した構造
17
ハッシング
ハッシュ表
(hash table)
とはハッシュ関数
h
を使って、要素x
があらかじめ準備したm
個の場所のうち、位置
h(x)
に格納される表[ハッシュ関数のもつべき性質]
・関数値の高速な算出が可能である
・要素となりうる
x
に対して、ハッシュ値h(x)
がm
個の位置にできるだけ偏りなく分布すること[よく用いられるハッシュ関数]
・
x
が整数の場合h(x)=x%m (x
をm
で割った余り)
・xが文字列の場合
h(x)=(Σord(x[i]))%m
ただし、
ord(a)
は文字a
の整数コード(ASCII, JIS, EUC
等)
であり、k
はx
の文字列長hash
は英語で「ごた混ぜにする」という意味。i=0 k-1
一般にデータはいろいろな周期のものを含んでいるため、
m
がデータの周期を約数にもつと関数値の衝突が起こり やすくなる。そのためm
としては素数を選ぶことが多い。しかし、どのようなハッシュ関数を選んでも衝突は避けられない!
アルゴリズムとデータ構造
2015 2015/12/02
18 衝突対処法
異なる要素
x,y
に対し、ハッシュ値が等しくなる(h(x)=h(y))
ことがある。そのような場合の対処法として次の2つがある。
1.
外部ハッシュ法、チェイニング(open hashing, chaining)
同じハッシュ値をもつ要素を、
その値に対応するバケットに格納する。
バケットは連結リストで実現できる。
2.
内部ハッシュ法、オープンアドレッシング(closed hasing, open addressing) x
を格納しようとしたときに、位置h(x)
がすでに使われている場合、新しいハッシュ値
h i (x) (i=1,2,…)
を 次々と求め、最初に見つかった空いている位置h i (x)に格納する。h i
としては、以下の関数などが使われる。h i (x)=(h(x)+i)%m
h(x)=x%m
の場合の2 32
5 55 15
insert(15,S)
2 32
5
55
15
19
外部ハッシュ法の基本操作
member(x,S) h(x)に対応するバケット内で値がxのものを探し、見つかればyes、
見つからなければ
no
を返す。Insert(x,S) h(x)
に対応するバケット内で値がx
のものを探し、見つかれば何もしない、見つからなければバケットに追加。
delete(x,S) h(x)
に対応するバケット内で値がx
のものを探し、見つかれば削除、見つからなければ何もしない。
基本操作の時間計算量
α=n/m :
占有率(n:
格納要素数, m:
バケット数)
最悪時間計算量
O(n)
(
全ての要素が同じハッシュ値をもつ場合)
平均時間計算量
O(α)
(n=O(m)
であればO(1))
2 32
5 55 15
member(12,S)
h(12)=2 no
Insert(15,S)
h(15)=5
18 88 48
delete(88,S)
h(88)=8 48
アルゴリズムとデータ構造
2015 2015/12/02
20 内部ハッシュ法の基本操作
member(x,S)
位置h(x)
から探し始め、h(x),h 1 (x),h 2 (x),…
の順でその位置の要素がx
と 等しいかをチェックする。等しいものがみつかったらyes
を返す。位置h i (x)
が空き(“empty”)
となるまでチェックし、見つからなければno
を返す。Insert(x,S)
位置h(x)
から探し始め、h(x),h 1 (x),h 2 (x),…
の順でその位置の要素がx
と 等しいかをチェックする。位置h i (x)
が空き(“empty”)
となるまでチェックし、x
と等しい要素が見つかれば何もしない。みつからなければ、検索途中で 見つけた空き(“empty” or “deleted”)
にx
を格納する。delete(x,S)
位置h(x)
から探し始め、h(x),h 1 (x),h 2 (x),…
の順でその位置の要素がx
と 等しいかをチェックする。位置h i (x)
が空き(“empty”)
となるまでチェックし、x
と等しい要素が見つかれば削除し”deleted”
のフラグを立てる。みつから なければ何もしない。基本操作の時間計算量
α=n/m :
占有率(n:
格納要素数, m:
バケット数)
最悪時間計算量O(n)
(
全ての要素が同じハッシュ値をもつ場合)
平均時間計算量
O(1/(1-α)) (x
が表にない場合)
O(-(1/α)log(1-α)) (x
が表にある場合)
どちらの場合もn=O(m)
であれば、O(1)
deleted empty
2 32 deleted
5 55 empty empty
15
member(12,S)
h(12)=2
no insert(12,S)
h(12)=2
12
delete(12,S)
21 内部ハッシュ法の平均時間計算量の証明
・
x
が表にない場合h 0 (x)(=h(x)),h 1 (x),…の順にハッシュ値の計算を行うものとする。
位置
h i (x)
で初めて空を見つける確率はn(n-1)
・・・(n-i+1)(m-n) m(m-1)・・・(m-i+1)(m-i)
である。(ただし、
i=0
のとき、上式は(m-n)/m
をあらわすものとする。)したがって、要素の比較回数の期待値は、
比較回数の定数倍の時間で計算できるので平均時間計算量は
O(1/(1-α)) (i +1) n(n − 1) (n − i +1)(m − n )
m(m − 1) (m − i + 1)(m − i )
i=0 n
∑ = (i +1)
i=0 n
∑ m(m n(n − − 1) 1) (n (m − − i i +1) + 1) # $ % 1 − m n − − i i & ' (
= (i + 1)
i=0 n
∑ m(m n(n − − 1) 1) (n (m − − i i +1) + 1) − i
i=1 n+1
∑ m(m n(n −1) −1) (n (m − − i i + +1) 1)
≤ n(n − 1) (n − i + 1) m(m − 1) (m − i +1)
i=0 n
∑
≤ n
m
#
$ % &
' (
i
i=0
∞
∑ = 1
1 − n m
= 1
1 − α
アルゴリズムとデータ構造
2015 2015/12/02
22 内部ハッシュ法の平均時間計算量の証明 (続き)
・
x
が表にある場合比較回数の期待値は、
n
個の異なる要素を空の表に 格納するのに必要な比較回数の平均に等しい。したがって
比較回数の定数倍で計算できるので、平均時間計算量は
O(- log(1-α))
(証明終わり)
1 α
確率
p
で生起する事象がk
回目で初めて生起するとした場合、k
の期待値は1/p
である という事実を使っている。つまり、確率(m-i)/m
で生起する事象では、k
の期待値はm/(m-i)
である。1
n m
… y= m
m-x
1 n
m
m − i ≤ 1 n
m m − x
0
∫
n i=0n−1
∑ dx
= m
n ln m
m − n = − 1
α ln(1 − α )
第 7 回 探索のためのデータ構造( 2 )
n
今日の内容:¨
今日は短い内容が二つあります。¨
前半: (発展内容)最適2
分探索木を学ぼう。n 「発展内容」なので、わからないときは飛ばしても良いです。(試験にでません)
n これは、検索のみで挿入と削除をしないときに、平衡二分探索木(第6回)よりも検索時間が 短くなるデータ構造を見つける話です。表を埋めることで、計算を高速に行う「動的計画法」の 例です。興味ある人はどうぞ!
¨
後半:(基本内容)「ハッシュ表」を学ぼう。n ハッシュ表は、平均的にO(1)時間で探索できる、実用的に効率が良い探索データ構造です。