1
Introduction to Algorithms
ハッシュ
Hash
16273001 高見玲
2
WHAT'S HASH?
3
Key に対応するValue を得たい
ex) コンパイラの記号表

辞書を表すデータ構造
4
直接アドレス表配列の般化
キーと格納先は1:1対応である必要
5
直接アドレス表の定義
普遍集合: から選択されるキー
を持つ動的集合を表現
すべての要素は異なるキーを持つと仮定
直接アドレス表:
配列の各位置: 枠(Slot)
集合がキー を含まなければ
U = {0, 1, . . . m − 1}
T = {0, 1, . . . m − 1}
k T[k] = nil
6
直接アドレス表の定義
計算時間(平均):
要素の探索時間: ->
O(1)
Θ(n) O(1)
7
直接アドレス表に必要となる操作
INSERT(挿入)
SEARCH(検索)
DELETE(削除)
8
直接アドレス表の問題点
普遍集合 が大きくなる-> 計算時間遅い
キー集合が である必要有
キーと格納先は1:1対応である必要
U
k << U
9
ハッシュ直接アドレス: キー に格納
ハッシュ: キー に格納
で枠の位置を決める操作: ハッシュする(Hashing)
k → 枠k
k → ハッシュ関数h(k)
h(k)

は普遍集合 から への写像h(k) U T = {0, 1, . . . m − 1}
h : U → {0, 1, . . . , m − 1}
10
ハッシュ表の利点
必要なメモリ: に縮小Θ(|K|)
ハッシュ表の問題点
写像先の衝突の発生
解決法: チェイン法, オープンアドレス法
11
チェイン法
Chaining
同枠にハッシュされた全ての要素を連結リストに格納
12
挿入の探索時間の評価
INSERT: をリスト の先頭に代入 ->
SEARCH: の中からキー をもつ要素を探査
DELETE: リスト から を削除->
x T[h(x. key)] O(1)
T[h(k)] k
T[h(x. key)] x O(1)
13
チェイン法の探査時間
ハッシュ表の負荷率
: 1つのチェインにある要素数の平均 (最悪 )
単純一様ハッシュ仮定(Simple Uniform Hashing)
n要素, 枠数mの α = n/m
α Θ(n)

失敗時: , 成功時:
ハッシュ表の枠数と表の要素数が比例:
Θ(1 + α) Θ(1 + α)
n = O(m)
α = n/m = O(m)/m = (1)
14
優れたハッシュ関数
単純一様ハッシュ仮定を満たす
基本満たさないので(乱数以外), ヒューリスティックに
求める
データ内に存在するパターンと独立であるべき(偏ら
ない)
基本数値-> 文字列であれば数値に直して求める
15
除算法
h(k) = k mod m
を決定する, 2のべき乗から離れているほどよい
問題点: ハッシュ先のバリエーションが少ない-> 衝突
が発生
m
16
乗算法
1. キー を乗じ, 整数部のみを抽出
2. 任意の数 を乗じ, 少数部を切り捨て
kに定数A(0 < A < 1)
m
h(k) = [m(kA mod 1)]
の選択に結果がさほど依存しない, 通常は
理想の
m m = 2
p
A ≈ ( − 1)/2 = 0.6180339887...5‾√
17
万能ハッシュ法
悪意のある代入時, 最悪探索時間はO(n)

ランダムにハッシュ関数を選べば起こりえない
へと写像する の集合
からランダムに抽出した についてキー の衝突が
のときに万能
Uを{0, 1, . . . m − 1} h(k) ℌ
ℌ h k, l
< 1/m
18
万能ハッシュ法の設計
全てのキー が に入る十分大きな素数 を
選ぶ
を
表す
は素数なので, これを法として整数論的に解ける(普遍
集合のサイズは枠数よりも十分に大きい)
k 0 < k < p − 1 p
で集合{0, 1, . . . , p − 1}, で集合{1, 2, . . . , p − 1}ℤp ℤ
∗
p
p

19
万能ハッシュ法の設計
任意の に対してハッシュ関数 を
に関する法をとることで定義
このようなハッシュ関数からなる族をランダムに選べ
ばよい
a ∈ , b ∈ℤp ℤ
∗
p
ha,b
p, m
= ((ak + b) mod p) mod mha,b
= { : a ∈ かつ b  ∈ }ℌpm
ha,b ℤp ℤp
20
オープンアドレス法
Open addressing
全ての要素をハッシュ表に格納する(チェイン法のよ
うにリストを有しない)
値がぶつかった場合, 次の要素を探査
探索は要素を発見or失敗まで継続する(キーを置ける空
の枠があるまで)
利点: ポインタを使用しないため容量減, 衝突減, 高速
化
21
オープンアドレス法
ハッシュ関数を拡張(探索番号の導入)
の探査列 は表を完全
に埋めるために の置換である必要
h : U × {0, 1, . . . , m − 1} → {0, 1, . . . , m − 1}
k ⟨h(k, 0), h(k, 1), . . . , k(k, m − 1)⟩
⟨0, 1, . . . , m − 1⟩
22
オープンアドレス法
挿入と検索は以下のようなかんじ
削除: nilを代入すると後で辿れなくなるので, Deleteを
明示的に入れる
23
オープンアドレス法の手法
一様ハッシュを仮定, キーの探査列は ある置換の
うち1つと等確率で一致 ( )
1つの数だけでなく1つの探査列を出力するように拡張
した単純一様ハッシュ
一様ハッシュの実現は困難-> ダブルハッシュ法などで
近似
m!個
Θ(m!)
24
線形探査法
以下のハッシュ関数を用いる
補助ハッシュ関数 を用いて線形に探査していく
問題点: 主クラスタ化(primary clustering)
h(k, i) = ( (k) + i) mod nh
′
(k)h
′
25
2次関数探査法
以下のハッシュ関数を用いる
は正の補助定数, 探査数(探査する位置)は で表さ
れる2次式より決定
探査列のバリエーション増加 , 主クラスタ化を防
止
問題点: 同じ初期探査位置を持つ2つのキーは同じ探査
列を持つ-> 副クラスタ化(secondary clustering)
h(k, i) = ( (k) + i + ) mod nh
′
c1 c2 i
2
,c1 c2 i
Θ(m)
26
ダブルハッシュ法
以下のハッシュ関数を用いる
ランダム置換と多くの性質を共有->最良
初期位置と次探査位置の2つが変化しうる-> キー に二
重依存, 探査列のバリエーション増加
ハッシュ表全体を探索するためには, 値 はハッシ
ュ表のサイズ と互いに素である必要
h(k, i) = ( (k) + i (k)) mod nh1 h2
k
Θ( )m
2
(k)h2
m
27
オープンアドレス法の解析
負荷率
一様ハッシュを仮定したとき, 探査列と置換数は一致
成功時の探査数期待値: 以下
失敗時の探査数期待値:
挿入時の探査数期待値:
α = n/m < 1
ln
1
α
1
1−α
1/(1 − α)
1/(1 − α)
28
完全ハッシュ法
Perfect Hashing
ハッシュ: キー集合が静的な場合大きさは変わらず, 最
悪時にも良い性能(ex. 予約語, CD)
探索に必要なメモリアクセス回数が最悪でもO(1)
29
完全ハッシュ法の実現
2段階の万能ハッシュ表を用いる(チェイン法の連結リ
ストの代わりに2段目に副ハッシュを使う)
ハッシュ関数をうまく選ぶとO(1)
参考文献[1] T. H. Cormen, C. Stein, R. L. Rivest, and C. E. Leiserson, アルゴリズムイントロダクション 第3版, Vol. 1,
2012.
[2] D. E. Knuth, Sorting and Searching, volume 3 of The Art of Computer Programming, Addusib-Wesley, 1973, 2nd
Edition, 1997
30

[アルゴリズムイントロダクション勉強会] ハッシュ