Transcript Document

データ構造と
アルゴリズム
第十一回
理工学部
情報システム工学科
新田直也
時間計算量のまとめ

時間計算量のまとめ登録
探索
削除
線形探索法
(最悪・平均)
O(1)
O(n)
O(n)
二分探索法
(最悪・平均)
二分探索木
(最悪)
O(n)
O(log n)
O(n)
O(n)
O(n)
O(n)
二分探索木
(平均)
AVL木探索
(最悪)
O(log n)
O(log n)
O(log n)
O(log n)
O(log n)
O(log n)
探索

探索: 表からデータを探し出す.
Key
Data
1
90
5
50
6
80
8
95
10
35
ハッシュ法の考え方(1)

Key値の取りうる範囲が,予めわかっている場合.
Key
Key
Data
1
90
5
50
6
80
8
95
10
35
→O(1)で探索できる.
Data
1
90
2
なし
3
なし
4
なし
5
50
6
80
7
なし
8
95
9
なし
10
35
配
列
な
ど
ハッシュ法の考え方(2)

前頁のようなデータ構造の問題点



Key値のとりうる範囲が広いと,データサイズは膨大に.
たとえば,半角10文字の文字列を Key に持つ場合:
データ数は,1208925819614629174706176個!!
→現実的なメモリ領域に収まらない.
メモリ領域に収まるよう圧縮しよう.(ハッシュ関数)
a
ab
aa
:
100種類の値
1208925819614629174706176種類の値
ハッシュ関数の例

すべての文字コードを加算し,100で割った余りを
求める.
文字列
ハッシュ値
int hash(char s[]) {
int i = 0;
int n;
for (n = 0; s[n] != 0; n++) {
i = i + s[n];
}
return i % 100;
}
one
22
two
46
three
36
four
44
five
26
six
40
seven
45
eight
29
nine
26
ten
27
ハッシュ関数を用いた登録,探索
1.
2.
3.
ハッシュ値の取りうる範囲と
同じサイズの配列を用意.
(前頁の例では,100個)
Key のハッシュ値を求める.
(”two”の場合,46)
ハッシュ値が指す配列要素
にデータを登録する.
(46番目の要素に登録)
文字列
ハッシュ値
one
22
two
46
three
36
four
44
five
26
six
40
seven
45
eight
29
nine
26
ten
27
ハッシュ値の衝突
1.
2.
3.
ハッシュ値の取りうる範囲と
同じサイズの配列を用意.
(前頁の例では,100個)
Key のハッシュ値を求める.
(”two”の場合,46)
ハッシュ値が指す配列要素
にデータを登録する.
(46番目の要素に登録)
→ ”five” と ”nine” のデータが
ぶつかる.(衝突)
文字列
ハッシュ値
one
22
two
46
three
36
four
44
five
26
six
40
seven
45
eight
29
nine
26
ten
27
チェイン法(1)

ハッシュ値が衝突すると,データが上書きされる.
key
“five”
“nine”
“zh”
“yi”
92
17
ハッシュ値
Data
0
なし
1
なし
:
:
204
26
39
:
:
99
なし
92?
17?
204?
39?
→同じ場所にデータを任意個記憶できるようにすればよい.
チェイン法(2)

同じハッシュ値を持つデータを連結リストでつなぐ.
ハッシュ表
key
“five”
“nine”
“zh”
“yi”
92
17
ハッシュ値
Data
0
NULL
1
NULL
:
:
204
26
39
:
:
99
NULL
“five”
92
“nine”
17
バケット
…
チェイン法(3)

チェイン法のデータ構造.
#define BUCKET_SIZE 100
struct CELL {
int key;
int data;
strucr CELL *next;
};
struct CELL *table[BUCKET_SIZE];
チェイン法の計算量

データ数をN,バケット数をBとする.



平均時間計算量: O(1 + N/B)
最悪時間計算量: O(N)
平均時間計算量について

Bを定数と考えると…
O(N)
オープンアドレス法



ハッシュして同じ場所を指した場合,別の場所を探す.
別の場所を探す手続きを再ハッシュと呼ぶ.
再ハッシュは繰り返し実行できる.
key
ハッシュ値
Data
0
“five”
“nine”
“zh”
1
204
:
:
26
92
:
:
53
17
:
:
99
オープンアドレス法の登録

オープンアドレス法の登録手続き:
x: キー, hk(x): 再ハッシュをk回繰り返して得られる値
1.
2.
3.
4.
5.
k := 0
hk(x) のバケットが空いているか?空いていれば 5. へ
k := k + 1
k = B ならエラー終了,そうでなければ 2. へ
hk(x)番目のバケットにデータを書き込む
再ハッシュの例

最も単純な例:

適当なハッシュ関数 h に対して
hk(x) = (h(x) + k) mod B

とする.
これは連続するバケットを順に調べていくことに対応.
オープンアドレス法の削除(1)

単純に削除を行うと問題が発生.
ハッシュ表
key
“five”
“nine”
“zh”
“yi”
ハッシュ値
92
17
Data
0
1
:
:
204
26
92
39
27
17
28
204
29
39
:
:
99
“nine”のデータを
「空き」にすると,
続きが探索できな
くなる.
孤立してしまう!!
オープンアドレス法の削除(2)

「削除済」という特別な値を用意し,続きがあることを示す.
ハッシュ表
key
“five”
“nine”
“zh”
“yi”
ハッシュ値
92
17
Data
0
1
:
:
204
26
92
39
27
削除済
28
204
29
39
:
:
99
“nine”のデータを
「削除済」に設定
する.
良い再ハッシュ法(1)

先に示した単純な再ハッシュ法は次のような問題を持つ.
ハッシュ値
Data
0
:
:
26
ハッシュ値26を持つ
データの系列
ハッシュ値28を持つ
データの系列
27
28
一度重なると
その後ずっと
重なってしまう
29
30
:
99
:
良い再ハッシュ法(2)

単純な再ハッシュ法では,以下の関係が成り立ってしまう.
hk1(x1) = hk2(x2) ⇒ hk1+1(x1) = hk2+1(x2)
hk(x) = (h(x) + k) mod B
ランダム置換(並べ替え)
k
hk(x) = (h(x) + nk) mod B
nk
オープンアドレス法の計算量

α = 登録バケット数 / 全バケット数
探索の平均時間計算量


連続領域で再ハッシュ:
成功: O((1-α/2)/(1-α))
失敗: O(1/2+1/(2(1-α)2))
ランダムに再ハッシュ:
成功: O(1/α・loge(1/(1-α)))
失敗: O(1/(1-α))
60
50
計算時間

40
連続領域(成功)
連続領域(失敗)
ランダム(成功)
ランダム(失敗)
30
20
10
0
0
0.2
0.4
0.6
α
0.8
1