[プロ技] ハッシュテーブルとハッシュ法

woody_1227 オーナー 公式アカウント

O(1)で検索するためのデータ構造とアルゴリズム
ログインすると、チェック機能を利用できるようになります。
ハッシュテーブル(ハッシュ表)
とそれに対応する を、インデックス(索引)で管理する
・データ操作
 ・検索、追加、更新、削除
・データ操作は、データの 一定時間[ ]で可能
に対して何らかの を行う
 →演算結果がキーに対するインデックス(索引)の値になればよい
 「
   …通常、非負整数(≧0)

ハッシュ法
・ハッシュ関数により得られたハッシュ値によって、ハッシュテーブルを参照する

ところで…
・ハッシュと聞いて、何をイメージしますか?
 ・ハッシュドポテト、ハッシュドビーフ、…
 ・食べ物以外にも、TwitterXのハッシュタグ
・そもそもハッシュとは
 ・細かく切り刻む、粉々にする、細切れにする、または、その断片
・情報科学でいうハッシュ
 ・元データを したものを表す数値や文字列を指す用語
  ・元データが細切れにされ「断片」になっている、というイメージに由来
 ・ハッシュの持つ情報量は、元のデータより
  ・ハッシュ値から元データを復元することは =ハッシュの

ハッシュ関数
・キーからハッシュ値を求める関数
・ハッシュ関数に求められる性質
 ・ハッシュ値はハッシュテーブルの →テーブルからはみ出したらダメ
 ・任意のキーに対するハッシュ値の分布が になる
  ・これは理想…実は難しい
  ・現実には、異なるキーに対するハッシュ値が同じになること[ハッシュ値の ( )]は避けられない

衝突(コリジョン)対策
・発生する頻度を少なくする
 ・ハッシュテーブルのサイズをできるだけ する
  ・サイズが大きいほど、ハッシュ値のとれる範囲は拡大→衝突の確率は下がる
 ・テーブルを にする
  ・通常ハッシュ関数は、ハッシュ値を求めるのにテーブルサイズで割った を使う
   …ハッシュ値がテーブルからはみ出さないようにするため
  ・素数で割った余りは散らばりやすい
・発生したらどうするか
 ・ハッシュ値を一定の規則で求め直す(再ハッシュ) …
 ・同一ハッシュ値のデータを同じエントリに格納する…
  ・同じハッシュ値を持つデータ=

オープンアドレス法

・削除の場合はちょっと注意
 削除の際は、削除済みを表す印をつけておく

オープンアドレス法の性能
・1回の探索に要する平均比較回数(理想的なハッシュ関数を想定)
 ・再ハッシュ hash(key, i) = (hash(key, 1) + (i - 1)) % T
 ・探索成功  (1 - a / 2) / (1 - a)
 ・探索失敗  1 / 2 + 1 / (2(1 - a)^2)
  aはハッシュテーブルの使用率
  テーブルサイズ:T, 格納データ総数:n
  a = n / T ( )

チェイン法

 同じハッシュ値を持つデータ(シノニム)を、 でつなぐ

チェイン法の性能
・探索の計算量(理想的なハッシュ関数を想定)
 ・ハッシュ値の計算…O(1)
 ・シノニムが存在するとき…リストの探索が必要
  ・テーブルの各エントリにおける、 ( )が分かればよい
   テーブルサイズ:T, 格納データ総数:n 平均何個?
  ・シノニムの探索に要する計算量…O(n/T)
 ・全体の計算量…O(1+n/T)
  ・テーブルサイズよりデータ数がずっと少ないとき(n << T)
    n/T ≈ 0(ゼロ)なので、O(1+n/T)=O(1+0)=
  ・テーブルサイズよりデータ数がずっと多いとき (n >> T)
    n/T ≈ nなので、O(1+n/T)=O(1+n)=

オープンアドレス法とチェイン法の比較
・オープンアドレス法
 ・実装は容易
 ・実用できるのは、データ数がテーブルサイズの80~90%程度まで
  ・データ数1000、使用率85%とすると、テーブルサイズは1200程度必要
  ・単純な再ハッシュはデータの塊を作りやすい
・チェイン法 … この授業で実装します
 ・実装は若干複雑
 ・実用できるのは、データ数がテーブルサイズの数倍程度まで
  ・データ数が1000なら、テーブルサイズは400~500程度でよい
  ・データ数が増えるとシノニムのリストが長くなる

チェイン法での実装(データ構造の定義)
typedef struct hash_element { //ハッシュテーブルに格納される一要素
char *key; //キー
char *value; //キーに対応する値
struct has_element *next; //次の要素(シノニム)へのポインタ
} HashElement;

typedef struct { //ハッシュテーブルはこのデータ型の配列
int count; //このエントリを共有するシノニムの数
HashElement *element; //格納する要素(キーと値)へのポインタ
} HashEntry;

HashEntry tbl[TBL_SIZE]; //TBL_SIZEはハッシュテーブルの大きさ
まとめ
・ハッシュテーブルの特徴
 ・原理的には、O(1)の検索が可能
  ・現実には、 の作り方と、 に大きく依存する
 ・データに がつけられない
  ・順序づけが必要な場合、別途ソートが必要
   ・順序づけを優先したいなら、AVL木や赤黒木などの平衡二分探索木を利用
 ・データ格納後のテーブルサイズ変更は
  ・ の再ハッシュが必要
・使用場面
 ・ のないハッシュ関数が用意でき、十分な が使える環境での検索
  ・連想配列、コンパイラやインタプリタでの予約語, 変数名, 関数名等の管理