ハッシュテーブルの基本
algorithmdata-structuresundergraduatelecture
data/lecture/information/algorithm/data-structures/data-structures-portal.lecture.n.md
1導入
この講義では、辞書 ADT をハッシュテーブルで実装する方法を説明する。衝突を連鎖法で処理する場合について、負荷率と計算量の関係を整理する。
2辞書 ADT
辞書 ADT は、キーの集合を管理し、キーに対応する値を記録する抽象データ型である。検索は、キーが存在すれば対応する値を返し、存在しなければ「未登録」を返す。挿入は、未登録のキーと値を追加し、登録済みのキーには対応値を置換する。削除は、登録済みのキーと対応値を除去し、未登録のキーには状態を変更しない。キーの順序は仕様に含まれない。
3ハッシュ関数とバケット
キーの全体を U、バケット数を m とする。ハッシュ関数 は
h:U\to\{0,1,\ldots,m-1\}
によってキーを配列の添字へ対応させる関数である。バケット は、同一の添字へ対応したキーを格納する領域である。キー k の操作では、まず h(k) に対応するバケットを選択する。
衝突 は、相異なるキー k_1,k_2 に対して h(k_1)=h(k_2) が成立することである。U の要素数が m より大きい場合、鳩の巣原理により衝突は不可避である。
4連鎖法
連鎖法 は、各バケットにキーと値の列を保持し、衝突した要素を同一の列へ格納する方式である。検索では h(k) のバケットだけを走査する。挿入と削除でも、同じバケット内でキーを照合する。連鎖を連結リストで実装する場合、操作時間はバケット内の要素数に依存する。
5負荷率と期待計算量
格納されているキーの個数を n とする。負荷率 は
\alpha=\frac{n}{m}
である。入力となるキー列を固定し、ハッシュ関数族から関数を無作為に選択したとき、各キーが m 個のバケットへ一様かつ独立に対応するという単純一様ハッシュ仮定を置く。期待値はこの無作為選択について取る。この仮定の下では、バケットの期待要素数は \alpha である。したがって、連鎖法による検索・挿入・削除の期待時間は O(1+\alpha) となる。\alpha を定数以下に維持すれば、各操作の期待時間は O(1) である。
これは任意のハッシュ関数に対する決定的な保証ではない。すべてのキーが単一のバケットへ集中する場合、検索・挿入・削除の最悪時間は O(n) となる。
6リサイズ
リサイズ は、負荷率が所定の閾値を超過したときに、より大きいバケット配列を確保し、すべてのキーを再配置する操作である。バケット数が変化するとハッシュ値の範囲も変化するため、既存の要素をそのまま複製するだけでは不十分であり、各キーのバケットを再計算する必要がある。
1 回のリサイズには O(n) 時間を要する。ただし、バケット数を定数倍に拡大する方式では、多数の挿入にリサイズ費用を配分できる。リサイズ後にも単純一様ハッシュ仮定を満たす関数を選択し、\alpha を定数以下に維持し、1 回のハッシュ計算を O(1) とする。このとき、挿入の償却期待時間は O(1) となる。
7適用範囲
- キーの完全一致による検索にはハッシュテーブルが適する。
- キーの大小順、範囲検索、最小値を直接扱う場合には、平衡探索木などの順序を保持するデータ構造が適する。
8まとめ
ハッシュテーブルは、ハッシュ関数でバケットを選択し、連鎖法で衝突を処理する。単純一様ハッシュ仮定と有界な負荷率の下では辞書操作を期待 O(1) 時間で実行できるが、最悪時間は O(n) である。