探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function)...

42
探索アルゴリズム

Upload: others

Post on 12-Jul-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

探索アルゴリズム

Page 2: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

探索とは?

キー

一致するものを探す

・・・・

・・・・

・・・・

・・・・

・・・・

:: :: ::

レコード

フィールド

Page 3: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

線形探索アルゴリズム(1) n=10, i =0,

target=54

a[i] : target

i++

START

END

=

i : n

return i return -1

<

前提:配列aにn個のデータが保存

処理:target と同じデータが蓄えられている配列要素の添え字を返し,ない場合は-1を返すフローチャートを記せ

Page 4: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

key data

table[0]

table[1]

tabel[2]

table[3]

table[n-1]

table[n]

table[199]

75 福崎慎也

101 渡邊滋之

17 大野綾子

28 川島祐毅

: :

64 仲野弘幸

番人

(sentinel)

87

番人による少し早い線形探索

Page 5: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

target = 54, i =0, a[n] = target

a[i] : target

i=i+1

START

END

=

i : N

return i return -1

<

番人を利用した線形探索アルゴリズム

※ループ毎に

iとn-1の比較が不要

Page 6: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

n=10, target = 54,

i =0

a[i] : target

i=i+1

START

END

=

前処理

i : N

return i return -1

<

n=10, target = 54,

i =0, a[n] = target

a[i] : target

i=i+1

START

END

=

前処理

i : N

return i return -1

<

番人なし 番人あり

2つの線形探索アルゴリズムの比較

Page 7: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

二分探索法(バイナリサーチ)

a[0]=1

a[1]=3

a[2]=4

a[3]=8

a[4]=13

a[5]=14

a[6]=18

a[7]=20

a[8]=21

a[9]=25

探すキーの値は 14 とする。

low→

middle→

high→

<14

a[0]=1

a[1]=3

a[2]=4

a[3]=8

a[4]=13

a[5]=14

a[6]=18

a[7]=20

a[8]=21

a[9]=25

low→

middle→

high→

>14

=middle+1

a[0]=1

a[1]=3

a[2]=4

a[3]=8

a[4]=13

a[5]=14

a[6]=18

a[7]=20

a[8]=21

a[9]=25

high→

low, middle→ =14

=middle-1

探索範囲

Page 8: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

二分探索アルゴリズム

(半分ずつ捨てるのがポイント)

サイズnの配列key(0~n-1)

においてsを探す

① first=0, last=n-1

② mid = (first+last)/2

③ key(mid)=s -> Found

key(mid)<s -> first=mid+1 Goto ②

key(mid)>s -> last=mid-1 Goto ②

上記アルゴリズムの問題点は? 完成させよ

Page 9: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

線形探索の計算量(比較の回数)は

最良1、最悪n、平均n/2

データ数nに対して O(n)

二分探索の計算量(比較の回数)は

2k-1≦n<2kのとき k回

つまり、データ数nに対して 約O(log2n)

Page 10: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

線形探索の計算量は O(n)

二分探索の計算量は O(log2 n)

n=1,000だったら?

n=1,000

log2n=約10 (なぜなら210=1,024)

100倍違う!

定数係数が少しくらい違ったって、

勝負は明らか!

Page 11: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

ビッグO のグラフ化

N 5 10 15 20 25

O(2n) 32 1024 32768 1048576 33554432

O(N2) 25 100 225 400 625

O(NlogN) 3.49 10 17.64 26.02 34.94

O(N) 5 10 15 20 25

O(logN) 0.69 1 1.17 1.30 1.39

O(1) 1 1 1 1 1

Page 12: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

O(1)

O(logN)

O(N)

O(NlogN) O(N2) O(2n)

ビッグオーの

グラフ化

Page 13: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

データの登録も考えると

登録(n要素当り) 探索(1回当り)

線形探索 O(n) O(n)

二分探索 O(n2) O(log n)

クイックソートで

O(n log n)

Page 14: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

登録1回あたりの探索回数をSとすると、

線形探索 O(n)+S・O(n)

二分探索 O(n log n)+S・O(log n)

n<<Sでないと、二分探索は有利に

ならない!

頻繁にデータ集合が変わるような応用には

二分探索は適さない

Page 15: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

ハッシュ法

Page 16: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

ハッシュ法

ハッシング(hashing)ともいう

hash: 切りきざむ

挿入・探索・削除がO(1)でできる

つまり、データの個数nに依存しない

理想の探索技法!?

Page 17: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

学生番号から氏名などを求めたい

2003年度に入学した学生だけを考えると、

70310001~70310101

でも、一般にキーはこのように順序よく

並んでいない

direct access という

配列の0番目から100番目に氏名を格納

→ (学生番号下3桁-1)番目の

配列要素を見ればよい

Page 18: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

英和辞書

• 5万語の英和辞書の全体をメモリにのせて使いたい

• 各単語のインデクス番号が分かれば,O(1)である単語の意味を知ることができる

インデクス番号 内容

1

2

3

…. hash:切り刻む

50,000

どうすれば 各単語の インデクス番号が 分かるか?

Page 19: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

語を数に変換する

• ASCII(アスキー)コード

–大文字,小文字,数字,記号などを0から255までの数で表現

– a:97, b:98, …, z:122

• 大文字,数字,記号などを使わないとしたら

–スペースを0として,a:1, b:2, c:3, …, z:26の27文字で表現できる

Page 20: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

語を数に変換する 方法1:単語の各文字に対応する数の総和を

インデクス番号とする

• cats = 3 + 1 + 20 + 19 = 43

• Dic[43] = cat:ネコ,猫科の動物・・・・ ここで,単語の最大文字数を10とすると,辞書の一番最後の文字は, (理論的には) zzzzzzzzzz(zが10個) = 26 X 10 = 260 50,000(単語あるとすれば) ÷ 260 = 192 → サイズ260の配列を準備すれば、 1つの配列要素に192語が該当する 例えば、単語の各文字に対応する数の総和がcatと同じ43になる単語 was(23+1+19), give(7+9+22+5), tend(20+5+14+4), ….

Page 21: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

語を数に変換する 方法2:桁位置を利用する(べき乗化)

• 数値の場合は0から9の10種類(10進数) – 各桁は10のべき乗

• 今回の前提では,スペース,aからzの27種類(27進数) – 各桁は27のべき乗

• cats = 3x273+1x272+20x271+19x270

= 60,337

• zzzzzzzzzz = 26x279 +26x278 +…+26x270

= 205,891,132,094,648

配列1要素あたり1バイトとすると, 約190TBのメモリが必要!! 1TB = 1024 * 1024 * 1024 * 1024 = 1,099,511,627,776 (約1兆バイト)

200兆以上!!

Page 22: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

語を数に変換する 方法2:桁位置を利用する(べき乗化)

fira firb firc fird fire firf firg 125146 125147 125148 125149 125151 125152

単語ではない

実在する単語

125150

Page 23: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

ハッシュ法

• 巨大な範囲の数を実用的なサイズの配列の添え字(インデクス)に変換

• 簡単な方法としては,モジュロ演算子(%)を使う

– %nは0からn-1までの数を作りだす

(値域:0~3) 23 % 4 = 3

13052 % 4 = 0 38 % 4 = 2

配列のインデクス = 巨大な数 % 配列サイズ

Page 24: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

ハッシュ関数(hash function)

キーの値xの集合 添字(ハッシュ値)

h(x)の集合

0,1,2,

・・・,99

× ×

× × ×

×

・・・

265 100

h(x)

大きな値域の数を小さな値域の数へと ハッシュ(切り刻む)する。文字列を 一定範囲の整数に変換すること。

Page 25: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

ハッシュ関数の例

int hash(char *s)

{ int i = 0;

while (*s)

i += *s++;

return i % 100}

a:97…………… z:122

アスキーコードの総和を

100で割った余りを配列

添字とする

この関数で求まるハッシュ値

の例

文字列 ハッシュ値

one 22

two 46

three

four

five

six

seven

eight

nine

ten

a 97 b 98 c 99 d 100 e 101 f 102 g 103 h 104 i 105 j 106 k 107 l 108 m 109 n 110 o 111 p 112 q 113 r 114 s 115 t 116 u 117 v 118 w 119 x 120 y 121 z 122

Page 26: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

ハッシュ表(テーブル)

ハッシュ値の例

文字列 ハッシュ値

one 22

two 46

three

four

five

six

seven

eight

nine

ten

0

1

…..

26 five

27 ten

28

29 eight

…..

ハッシュ関数を使って データを挿入した配列

Page 27: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

ハッシュ(1) 問題1:

以下のハッシュ関数を用いて、表の各文字列に対応する

ハッシュ値を求めよ。

int hash(char *s) { int i = 0; while (*s) i += *s++; return i % 11}

a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11, l:12, m:13, n:14,o:15, p:16, q:17, r:18, s:19, t:20, u:21, v:22, w:23, x:24, y:25, z:26

ハッシュ関数

アルファベットに対応する数値

文字列 ハッシュ値

fukuzaki

watanabe

oono

kawashima

nakano

miura 例:yamaguti = (25+1+13+1+21+20+9) % 11 = 2

Page 28: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

異なるキーが同じハッシュ値に 写像されたら、どうするか?

チェイン法

オープンアドレス法

衝突の処理

大きく分けて

Page 29: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

チェイン法

ハッシュ表の同じ場所に写像された

データを連結リストにつなぐ

ハッシュ表は連結リストの先頭を指す

ポインタの配列

Page 30: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

A B

D E F

H I

ハッシュ表

Page 31: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

オープンアドレス法

ある一定の方法で,空セルを探して,

そこに新たな項目を挿入する方法

①線形探査(linear probing)

②平方探査(quadratic probing)

③ダブルハッシュ(double hashing)

Page 32: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

h(x)=h0(x)

h1(x)

h2(x)

h3(x)

ハッシュ表

::

::

オープンアドレス

法は、ハッシュ表の

中で仮想的な連結

リストを作るようなもの

ただし、次の要素は

ポインタでなく、

再ハッシュ関数に

よって決まる

Page 33: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

オープンアドレス法:線形探査

• 配列を単純にシーケンシャルに辿って空きセルを探すやり方 0

1

…..

26 five

27 ten

28

29 eight

…..

nine = 110+105+110+101 = 426 ハッシュ値= 426%100 =26

衝突

衝突 nine

OK

Page 34: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

再ハッシュ(rehash)

k回目にアクセスする場所: hk(x)

xはキー、k=0,1,2,・・・,B-1

最も簡単な再ハッシュ関数は

オープンアドレス法:線形探査 (2)

𝒉𝒌 𝒙 = 𝒉 𝒙 + 𝒌 % 𝑩

𝐵:ハッシュ表 配列 の大きさ

ℎ 𝑥 :最初のハッシュ関数

Page 35: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

オープンアドレス法:線形探査の問題点

0

…..

25

26 five

27 ten

28 nine

29 eight

30

この状態でさらにハッシュ値が 26のキーを挿入する場合 データが連続してしまい, 効率が落ちる

クラスター化

Page 36: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

オープンアドレス法:平方探査

線形探査のように,隣接するセルに挿入してい

くとクラスターができやすいので,もっと離れた

場所に挿入しようというやり方

注意点:配列のサイズを素数にしなければ 同じ場所を探し続けることがある

𝒉𝒌 𝒙 = 𝒉 𝒙 + 𝒌𝟐 % 𝑩

𝐵:ハッシュ表 配列 の大きさ

ℎ 𝑥 :最初のハッシュ関数

Page 37: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

オープンアドレス法:平方探査の問題点

サイズ59の配列(要素7に値が入っているとする)に, 184,302,420,538というキーを 順番に挿入することを考えると

184 % 59 = 7 → 1ステップで配列の要素8へ 302 % 59 = 7 → 2ステップで配列の要素11へ 420 % 59 = 7 → 3ステップで配列の要素16へ 538 % 59 = 7 → 4ステップで配列の要素23へ

第2種クラスター化

Page 38: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

オープンアドレス法:ダブルハッシュ

• キーの値によって探査の歩幅が異なるようにする方法

• キーに対して2度目のハッシュを行い,得られた結果をステップ幅として使う

𝒉𝒌 𝒙 = 𝒉 𝒙 + 𝒌 ∗ 𝒉𝒔 𝒙 % 𝑩

𝒉𝒔 𝒙 = 𝑪 − (𝒙 % 𝑪) % 𝑩

𝐵:ハッシュ表 配列 の大きさ

ℎ 𝑥 :最初のハッシュ関数

𝐶:定数(配列サイズより小さい素数)

Page 39: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

オープンアドレス法:ダブルハッシュの注意点

• 最初のハッシュ関数と同じであってはならない

• 0が作られることのある関数であってはならない

• ハッシュ表のサイズは素数でなければならない

• サイズ59の配列(要素7に値が入っているとす

る)に,184,302,420,538というキーを順番に挿入することを考えると?

Page 40: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

オープンアドレス法:ダブルハッシュの注意点

hk x = h x + k ∗ hs x % 59

hs x = 11 − (x % 11) % 59 (𝐵 = 59, 𝐶 = 11)とすると

h 184 = 184 % 59 = 7

h 302 = 302 % 59 = 7 hs 302 = 11 − (302 % 11) % 59) = 6 h1 302 = 7 + 1 ∗ 6 % 59 = 13

→ 配列の要素13へ

h 420 = 420 % 59 = 7 hs 420 = 11 − (420 % 11) % 59) = 9 h1 420 = 7 + 1 ∗ 9 % 59 = 16

→ 配列の要素16へ

h 538 = 538 % 59 = 7 hs 538 = 11 − (538 % 11) % 59) = 10 h1 538 = 7 + 1 ∗ 10 % 59 = 17

→ 配列の要素17へ

hs 184 = 11 − (184 % 11) % 59) = 3 h1 184 = 7 + 1 ∗ 3 % 59 = 10

→ 配列の要素10へ

Page 41: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

良いハッシュ関数とは

• 手早い計算

– ハッシュ法の利点はスピードなので,ハッシュ関数は高速であるべき

• ランダムキー

– Index = key % arraySizeで得られるインデクスもランダム(均等)に分布

• ノンランダムキー

– テーブルサイズには素数を使う

– 多くのキーと配列サイズに共通の公約数がある場合,それらが同じ位置へハッシュされるため

Page 42: 探索アルゴリズム...2017/10/27  · ハッシュ関数(hash function) キーの値xの集合 添字(ハッシュ値) h(x)の集合 0,1,2, ・・・,99 ×

ハッシュ(2) 問題1:

(2) (1)の表に示した文字列を上から順番に、要素数11のハッシュ表に格納せよ。

(3)衝突が発生した場合には、チェイン法とオープンアドレス法でそれぞれどのように衝突が回避されるかを図で示せ。

(4) オープンアドレス法は線形探査とダブルハッシュの両方を

示すこと。線形探査とダブルハッシュのハッシュ関数は以下のとおり。

k回目にアクセスする場所(k=0, 1, 2, …, 10)

線形探査のハッシュ関数

ダブルハッシュのハッシュ関数

ℎ𝑘 𝑥 = ℎ 𝑥 + 𝑘 % 𝐵

ℎ𝑘 𝑥 = ℎ 𝑥 + 𝑘 ∗ ℎ𝑠 𝑥 % 𝐵

ℎ𝑠 𝑥 = 𝐶 − (𝑥 % 𝐶) % 𝐵

𝐵 = 11, 𝐶 = 7 とする