Subsections

4 ハッシュマップ

4.1 基本的な考え方

単語のスペルから直に配列の添え字の値が導くことが出来れば,$ O(1)$ の計算量で済む. これはとても高速である.たとえば,表1に示した単語データベースのよ うなものを配列に格納することを考える.ただし,以下の条件を課す. 次のようにすれば,スペルから配列の値を求めることができる.

このようにスペルから直接添え字の値が計算できる配列に英単語を格納すると,とても高 速に探索,削除,追加ができるデータ構造となる.すべて,計算量のオーダーは$ O(1)$ で ある.しかし,この方法をよく考えると大きな問題がある.巨大なメモリー空間が必要な のである.配列の最大の添え字は, $ 1\times27^9-1=7625597484986$ となりとても現在のコンピューター で取り扱うことができない.

このような配列に単語を格納すると,ほとんどその中は空になる.単語の数はそれほど多 くない.諸君の英和辞典の単語数を調べてもよく分かる.そこで,この配列の添え字を 099999に圧縮することを考える.新たな添え字をjとすると,

	j=i%100000;
 
とすれば良い.100000で割った余りとすれば,099999の値が得られる. このようにして,データにアクセスする方法をハッシュ法と言う.得られた値(099999)をハッシュ値と言い,キーを変数として,それを求める関数をハッシュ関数 と言う.

このようにすると,明らかに以下の問題点がある.

これについて,以降,教科書に沿って説明する.

4.2 ハッシュ値の決め方

ハッシュを使う場合,配列にそのままデータを入れないで,データを表すポインターを入 れる方が便利である.ポインターが表すものを構造体とすれば,かなり柔軟に対応できる. 後で述べるがハッシュ値の重複(衝突)対策でリストやツリー構造を使う場合も対応が容易 である.

ハッシュ法を使うためには,教科書に書いてあるとおり,以下のような動作が必要である.

ハッシュ表は,データを示すポインターを入れる配列である.キーを決めるとハッシュ関 数を計算してハッシュ値が決まる.このハッシュ値がこの配列の添え字の値となる.そし て,そこに格納されている配列の値(ポインター)により,データにアクセスする.

ハッシュ表を作るときにはデータ数よりも大きいことが望ましい.そうしないと,異なっ たキーでも同じハッシュ値となり,衝突が発生し,データの探索スピードが落ちてしまう. 衝突の問題は後で述べるので,ここではハッシュ関数の作り方を説明する.ハッシュ表の 大きさは素数とすることが望ましい.こうすることにより,キーのどのビットが変化して もハッシュ値の値を変化させることができる.

ハッシュ関数は,一般に,次の2つの手順により成り立っている.

最初のキーから整数値を導き出す方法は,いろいろある.これについては,教科書の方法 を説明する.一方,これをハッシュ表の大きさの整数に直す方法は,大体決まっている. キーから導き出された整数をハッシュ表の大きさで割って,その余りとするのである.

4.3 ハッシュ値の重複対策

異なるキーであっても,同じハッシュ値となることがある.これが多いとハッシュ法の効 果が薄いのであるが,どうしても避けることができない.プログラマーはその対策を講じ なくてはならない.教科書に書かれている方法は,次の通りである. これらについては,教科書を用いて説明する.


ホームページ: Yamamoto's laboratory
著者: 山本昌志
Yamamoto Masashi
2006-01-30


no counter