情報工学概論 (アルゴリズムとデータ構造) 第7回 11.3.3 万能ハッシュ法 • 運が悪いと,n 個のキーが同じスロットにハッシュさ れ,平均検索時間が (n) になってしまう • 万能ハッシュ法 (universal hashing) では,ハッ シュ関数をランダムに選択する • どのように意地悪くキーを選択しても,平均として 良い性能を示す. 2 • H: キーの普遍集合 U から値域 {0,1,...,m1} へのハッシュ関数の有限集合 • H が万能 (universal) ⇔ 全ての異なるキーの 組 x, y U に対し,h(x) = h(y) となるハッシュ 関数 h H の個数がちょうど |H|/m • ハッシュ関数を万能な H の中からランダムに選 んだときに,x と y が衝突する確率が 1/m • これは h(x) と h(y) が値域 {0,1,...,m1} からラ ンダムに選択されたときの衝突確率に等しい 3 定理 11.3 h を万能な集合から選択されたハッシュ関 数とする.h を用いて n 個のキーをサイズが m の ハッシュ表にハッシュする. 衝突はチェイン法で解 消する.このとき,キー k のハッシュ先のリストの長 さの期待値 E[nh(k)] は 高々α(キーが表に存在しないとき) 高々1+α(キーが表に存在するとき) 期待値の計算は全てハッシュ関数に関して行い, キーの分布については何も仮定しないことに注意 4 証明:異なるキーのペア k, l に対して,指標確率変数 1 (h(k ) h(l )) X kl を定義する. 0 (h(k ) h(l )) ハッシュ関数の定義より,1つのキーのペアが衝突を 起こす確率は高々 1/m.つまり Pr{h(k)=h(l)}1/m よって E[Xkl] 1/m. キー k に対し,k 以外で k と同じスロットにハッシュさ れるキーの個数を確率変数 Yk で表す. Yk X kl lT l k 5 1 EYk E X kl EX kl lT lT lT m l k l k l k かつ l : l T and l k n • k T のとき nh( k ) Yk 従って En EY n h(k ) k m • k T のとき, キー k はリスト T[h(k)] に存在し, カウント Yk には k は含まれていないので nh( k ) Yk 1 かつ l : l T and l k n 1 従って Enh ( k ) n 1 EYk 1 1 1 m 6 万能ハッシュ関数族の設計 • どんなキー k も 0 から p-1 までの範囲に入るような 十分大きな素数 p を選ぶ.p > m を仮定. • ha ,b (k ) (( ak b) mod p ) mod m と定義 ただし a {1,2,…,p-1}, b {0,1,,…,p-1}. m は素数でなくてもいい. • 定理11.5: ハッシュ関数のクラス * H p,m ha,b : a Z p , b Z p は万能である. • 証明:相異なるキー k, l Zp を考える.ハッシュ関 数 ha,b に対し r = (ak+b) mod p 7 s = (al+b) mod p と置く. • 命題:r s rs a(kl) (mod p) である. a も kl も法 p の下で 0 ではない. p は素数だから右辺の積も 0 ではない. • (k,l) を固定する.p(p1) 個存在するハッシュ関数 のパラメタのペア (a,b) は, (k,l) を異なるペア (r,s) に写像する. a (r s) (k l ) 1 mod p mod p b r ak mod p • r s であるペアは p(p1) 個存在するので, (a,b) と (r,s) には1対1対応がある. • (a,b) を一様ランダムに選べば, (r,s) も一様ランダ ム. 8 • 従って,相異なるキー k と l が衝突する確率は, 法 p の下で相異なる r と s をランダムに選択したと きに r s (mod m) となる確率に等しい. • r を固定すると,r 以外の p1 個の値の中で r s (mod m) となる s の個数は高々 p m 1 p 1 p 1 m 1 m m • よって,s と r が衝突する確率は高々 1/m • 従って,任意の異なる値 k,l Zp のペアに対し 1 Prha ,b (k ) ha ,b (l ) m つまり H p,m ha,b : a Z *p , b Z p は万能 9 乱数発生法 • {0, 1, …, p1} の整数を一様ランダムに生成 – C言語 int x; x = rand() % p; // 整数乱数を p で割った余り – Fortran real r integer x call RANDOM_NUMBER(r) ! 0 <= r < 1 の実数乱数 x = INT(r * p) 10 乱数の種の設定 • 現在時刻を乱数の種にする • C言語 srand((int)clock()); srand((int)time(NULL)); • Fortran call random_seed() 11 12. 2分探索木 • 探索木: SEARCH, MINIMUM, MAXIMUM, PREDECESSOR, SUCCESSOR, INSERT, DELETE等が利用できる動的集合用データ構造 • 辞書やプライオリティーキューとして利用できる • 基本操作は木の高さに比例した時間がかかる – ランダムに構成された2分探索木の高さ: O(lg n) – 最悪時: O(n) • 最悪時でも O(lg n) に改良できる (2色木) 12 12.1 2分探索木とは何か? • 各節点は key, left, right, p フィールドを持つ • 2分探索木条件 (binary-search-tree property) – 節点 y が x の左部分木に属する⇒ key[y]key[x] – 節点 y が x の右部分木に属する⇒ key[x]key[y] 2 3 5 7 3 2 7 5 5 8 5 8 13 木の中間順巡回 • 木の中間順巡回 (通りがけ順, inorder tree walk – 根の左部分木に出現するキー集合 – 根のキー – 右部分木に出現するキー集合の順にキーを出力 • 木の根から辿ると,全てのキーをソートされた順 序で出力できる 5 • (n) 時間 INORDER_TREE_WALK(node x) { if (x != NIL) { INORDER_TREE_WALK(left(x)); print(key(x)); INORDER_TREE_WALK(right(x)); } } 3 2 3 2 5 5 5 7 7 8 8 14 その他の巡回法 • 先行順巡回 (行きがけ順, preorder tree walk): 根節点を先に出力し,次に左右の部分木を出力 • 後行順巡回 (帰りがけ順, postorder tree walk): 先に左右の部分木を出力し,最後に根節点を出力 POSTORDER_TREE_WALK(node x) PREORDER_TREE_WALK(node x) { { if (x != NIL) { if (x != NIL) { POSTORDER_TREE_WALK(left(x)); print(key(x)); POSTORDER_TREE_WALK(right(x)); PREORDER_TREE_WALK(left(x)); PREORDER_TREE_WALK(right(x)); print(key(x)); } } } } 15 12.2 2分探索木に対する質問操作 • 質問操作は高さに比例した時間で終了する • 探索: 2分探索木の中から,ある与えられたキーを 持つ節点のポインタを求める(存在しなければNIL) TREE_SEARCH(node x, data k) { if (x == NIL || k == key(x)) return x; if (k < key(x)) return TREE_SEARCH(left(x),k); else return TREE_SEARCH(right(x),k); } 16 探索の正当性 • キー k が見つかったら探索を終了する • k が key(x) より小さい場合 – 2分探索木条件より,k は x の右部分木にはない – 左部分木に対して探索を続行する • k が key(x) より大きい場合 – 右部分木に対して探索を続行する • 探索する節点は根からのパスになる – 実行時間は O(h) (h: 木の高さ) 17 • 再帰はwhileループにすることができる ITERATIVE_TREE_SEARCH(node x, data k) { while (x != NIL && k != key(x)) { if (k < key(x)) x = left(x); else x = right(x); } return x; } 18 最小値と最大値 • 最小/最大のキーを持つ要素のポインタを 返す • O(h) 時間 TREE_MINIMUM(node x) { while (left(x) != NIL) { x = left(x); } return x; } TREE_MAXIMUM(node x) { while (right(x) != NIL) { x = right(x); } return x; } 19 次節点と前節点 • 2分探索木のある節点が与えられたとき,木 の中間順 (inorder) で次/前の節点を求める • O(h) 時間 TREE_SUCCESSOR(node x) { node y; if (right(x) != NIL) return TREE_MINIMUM(right(x)); y = p(x); while (y != NIL && x == right(y)) { x = y; y = p(y); } return y; } 20 x が右部分木を持つ場合 • x の次節点は,x 以上の要素で最小 ⇒ x の次節点は, x の右部分木の最小要素 = TREE_MINIMUM(right(x)) x 2 7 8 5 5 次節点 21 x が右部分木を持たない場合 • x の親を y とする • x が,x の親の右の子ならば,親は x 以下 • y は,x を左部分木に持つ x の祖先で最も x に近いもの 次節点 y = p(x); while (y != NIL && x == right(y)) { x = y; y = p(y); } return y; 2 9 y 5 yx 3 7 5 yx 8 x 22 定理 12.2 高さ h の2分探索木上の動的集合演 算 SEARCH, MAXIMUM, MINIMUM, SUCCESSOR, PREDECESSOR は O(h) 時間で実行できる 23 12.3 挿入と削除 • 要素を挿入/削除したあとも2分探索木条件が 満たされる必要がある • 挿入は比較的簡単 • 削除は複雑 • どちらも O(h) 時間 24 5 挿入 3 z 6 7 y TREE_INSERT(tree T, node z) x { 2 5 z 6 8 node x,y; y = NIL; x = root(T); while (x != NIL) { // z を挿入する場所 x を決める y = x; if (key(z) < key(x)) x = left(x); 挿入場所は必ず葉 else x = right(x); } // y は x の親 p(z) = y; // z の親を y にする if (y == NIL) root(T) = z; // T が空なら z が根節点 else if (key(z) < key(y)) left(y) = z; // y の子を z にする else right(y) = z; 25 } 削除 • 探索木から節点 z を削除する • z が子を持たない場合 – z の親と z の子を結ぶ 3 z – z の親 p(z) を変更する • z が子を1つ持つ場合 3 2 2 5 5 5 7 z 8 8 26 削除: z が子を2つ持つ場合 • z の次節点は左の子を持たない • z の場所に y を入れ,元の y を削除する 15 z 15 5 6 3 3 12 10 y 6 12 13 10 13 7 7 27 TREE_DELETE(tree T, node z) { node x, y; if (left(z) == NIL || right(z) == NIL) y = z; // z の子の数が1以下 else y = TREE_SUCCESSOR(z); // z は2つの子を持つ if (left(y) != NIL) x = left(y); else x = right(y); // x は y の子 if (x != NIL) p(x) = p(y); // y を削除する if (p(y) == NIL) root(T) = x; // y が根なら x を根に else if (y == left(p(y))) left(p(y)) = x; // y の親と子をつなぐ else right(p(y)) = x; if (y != z) { key(z) = key(y); // y の内容を z に移動 // y の付属データを z にコピー } return y; // 不必要な y を回収 28 } 12.4 ランダムに構成された2分探索木 • 2分探索木上の基本操作は O(h) 時間で実行 可 • 要素の挿入削除を繰り返すと探索木の高さ h は変化する • n 個の相異なるキーをランダムな順序で挿入し た2分探索木の高さを解析する • 高さの期待値は O(lg n) 29 • 仮定 – 入力キーの n! 種類の順列がどれも等確率で出現する – 全てのキーは異なる • 確率変数の定義 – Xn: n 個のキー上のランダムに構成された2分探索木の 高さ – Yn = 2Xn 指数高さ – Rn: n 個のキーの中での根のキーの順位 (rank) Rn = i なら,根の左部分木は i1 個のキー上の ランダムに構成された2分探索木,右部分木は ni 個のキー上のランダムに構成された2分探索木 30 • 2分探索木の高さは根の左右の部分木の高さの 大きいほう+1. Rn = i のとき X n max X i 1 , X n i 1 Yn 2 max Yi 1 , Yn i • Y1 = 1. 便宜上 Y0 = 1 と定義する. • 指標確率変数 Z n,1 , Z n, 2 ,, Z n,n を次のように定義 Rn i 1 Z n ,i IRn i 0 それ以外 • Rn の値は {1,2,…,n} の任意の要素を等確率で 取るから,Pr{Rn = i} = 1/n (i=1,2,…,n) よって 1 EZ n ,i n 31 • 根の順位が i のときだけ Zn,i = 1 になるから n Yi Z n ,i 2 max Yi 1 , Yn i i 1 • E[Yn] が多項式であることが示せれば, E[Xn] が O(lg n) であることが示せる. • Zn,i は Yi1 とも Yni とも独立 – 根の左部分木内の各要素は根よりも小さい,つまり 順位が i より小さい i1 個のキー上のランダムに構成 された木である. – この部分木は順位の制約がないi1 個のキー上のラン ダムな木と同じ – 部分木の高さ Yi1 と根の順位 Zn,i は独立 32 n EYi E Z n ,i 2 max Yi 1 , Yn i i 1 EZ n ,i 2 max Yi 1 , Yn i n (期待値の線形性) i 1 EZ n ,i E2 max Yi 1 , Yn i n (独立性) i 1 2 n Emax Yi 1 , Yn i n i 1 2 n EYi 1 EYn i n i 1 4 n 1 EYi n i 0 33 • 1 n 3 EYn 4 3 を示す 1 3 1 0 Y0 EY0 4 3 4 1 1 3 1 1 Y1 EY1 4 3 4 n 1 EYn EYi n u 0 4 n 1 1 i 3 n u 0 4 3 1 n 3 n 4 1 n 3 4 3 34 • 関数 f(x) = 2x は上に凸であるから 2 E X n EY E2 Xn n • 以上より 1 n 3 Olog n EX n log EYn log 4 3 • 定理12.4 n 個のキー上のランダムに構成さ れた2分探索木の高さの期待値は O(lg n). 35 36 補題 13.3 空の2分探索木に n 個の相異なるキーk1, k2,...,knをこの順序で挿入して得られる木をTとする. 1 i < j n に対し,T の中で ki が kj の先祖である ための必要十分条件は ki = min{kl: 1 l i かつ kl > kj} (k1から ki で kj より大きいものの中で最小) または ki = max{kl: 1 l i かつ kl < kj} 15 (k1から ki で kj より小さいものの中で最大) 6 挿入順 (一例) 15, 6, 12, 3, 10, 7, 13 12 3 10 kj 7 ki 13 37 証明: (必要性) ki が kj の先祖だと仮定する. kj < ki とし, ki = min{kl: 1 l i かつ kl > kj} が成り 立たないと仮定する.つまり, kj < km < ki となる km (m < i) が存在する. kj は km の左の部分木, ki は km の右の部分木に なり, ki が kj の先祖という仮定に矛盾する. kj > ki の場合も同様. 15 3 kj 2 km 5 6 ki 12 3 10 kj 7 ki 13 38 証明: (十分性) ki は, k1から ki で kj より大きいもの の中で最小と仮定する.探索木の根から ki までの パス上の節点 x を考える. ki < x のとき, kj < ki より kj < x x < ki のとき, x > kj とすると x は仮定を満たさない ので x < kj 15 よって根から kj へのパスは ki を通る. x つまり ki は kj の祖先 6 12 3 10 kj 7 ki 13 39 系13.4 空の2分探索木に n 個の相異なるキーk1, k2,...,kn をこの順序で挿入した結果を T とする. kj (1 j n) に対し,Gj と Lj を Gj = {ki: 1 i j かつ kl > kj である全ての l i に 対して kl > ki > kj} Lj = {ki: 1 i j かつ kl < kj である全ての l i に 対して kl < ki < kj} とする.このとき,根と kj を結ぶパス上に現れる キーの集合は Gj Lj に一致し, kj の T におけ る深さ d(kj, T) は d(kj, T) = |Gj| + |Lj| 40 Gj 21 Lj 9 25 12 4 10 3 7 29 19 26 17 kj 6 18 キー 21 9 4 25 7 12 3 10 19 29 17 6 26 18 Gj’ 21 25 19 29 ←kj より大きい Gj 21 19 ←最小値を更新 Lj’ 9 4 7 12 3 10 ←kj より小さい 41 Lj 9 12 ←最大値を更新 Gj のサイズの解析 • Gj: kj より大きいキーの中で,今までの最小値を 更新したものの集合 • n 個の異なるキーが1つずつ動的集合に挿入さ れたと仮定する • キーの全ての順列が同じ確率で出現するときに, 集合の最小値が何回変化するか求める • i 番目に挿入されたキーを ki とする (1 i n) • 最初の i 個の中で ki が最小値の確率 = 1/i 42 • 集合の最小値の変更回数の期待値は n 1 Hn i 1 i 補題 13.5 n 個の相異なる数のランダム順列を k1,k2,...,kn とし,|S| を,集合 S={ki: 1 i n, かつ, 全ての l < i についてkl >ki} の大きさを表す確率変数とする.このとき Pr{|S| (+1)Hn} 1/n2 ( 4.32 は (ln 1) = 2 を満たす数) 43 証明: 集合 S の大きさは n 回のベルヌーイ試行 から決定されるとみなすことができる. i 回目の試行が成功する確率は 1/i. 以下の定理を使う. 定理 6.6 i = 1,2,...,n に対して i 番目の試行の 成功確率が pi である n 回のベルヌーイ試行 の列を考える.Xを全成功回数を表す確率変 数とし, = E[X] とおく.このとき r > に対し r e PrX r r 44 > 1 より Pr| S | ( 1) H n Pr| S | H n H n eH n H n (1 ln ) H n e e (ln 1) ln n n (ln 1) 1/ n2 45 定理 13.6 n 個の相異なるキー上のランダムに構 成された2分探索木の高さの平均は O(lg n) 証明 n 個のキー上のランダム順列をk1,k2,...,kn とし,空の2分探索木にこれらをこの順序で挿入 した結果を T とする.与えられたキー kj の深さ d(kj,T) が少なくとも t である確率を考える. 系13.4 より, kj の深さが少なくとも t ならば,集合 Gj, Lj のどちらかはサイズが t/2 以上.よって Pr{d (k j , T ) t} Pr{| G j | t / 2} Pr{| L j | t / 2} 46 Pr{| G j | t / 2} Pr ki : 1 i jかつkl ki k j for all l i t / 2 Prki : i nかつkl ki for all l i t / 2 Pr| S | t / 2 Pr{| L j | t / 2} Pr| S | t / 2 Prd (k j , T ) t 2 Pr| S | t / 2 t = 2(+1)Hn とすると Prd (k j , T ) 2( 1) H n 2 Pr| S | ( 1) H n 2/n 2 47 2分探索木には n 個の節点が存在する.少なくと も1つの節点が高さ 2(+1)Hn 以上である確率 は高々 n(2/n2) = 2/n. 2分探索木の高さは確率 (12/n) 以上で 2(+1)Hn未満,確率 2/n 以下で n 以下.よって 高さの期待値は高々 (2( 1) H n )(1 2 / n) n(2 / n) O(lg n) 48
© Copyright 2025 ExpyDoc