01
衝突なし — O(1) という約束が前提にしている型
わかっていること: どの鍵も別々のスロットに入る。占有率 α = n/m は 1 未満で、ハッシュは鍵を表全体に均等にばらけさせている。
探索規則: h(k) = k mod m, α = n/m
計算例: 鍵 0–5 を m = 8 に h(k) = k mod 8 で入れる → スロット 0–5、各 1 回の探索。α = 0.75、平均探索回数はちょうど 1.00
この型を開く: 衝突なしインタラクティブな数学・理科レッスン (ノ◕ヮ◕)ノ*:・゚✧
ハッシュ表 — 鍵がどこに落ちるか、そして二つが同じ場所に落ちたら
ハッシュ表が O(1) なのは、鍵が散らばっているあいだだけです。決め手は二つの問いです。ハッシュ関数は鍵をばらけさせているか。そして二つが衝突したとき、二つ目をその場所にぶら下げるのか、別の場所を探しに行くのか。占有率 α = n/m が衝突の頻度を決め、戦略が一回あたりの代償を決めます。
01
わかっていること: どの鍵も別々のスロットに入る。占有率 α = n/m は 1 未満で、ハッシュは鍵を表全体に均等にばらけさせている。
探索規則: h(k) = k mod m, α = n/m
計算例: 鍵 0–5 を m = 8 に h(k) = k mod 8 で入れる → スロット 0–5、各 1 回の探索。α = 0.75、平均探索回数はちょうど 1.00
この型を開く: 衝突なし02
わかっていること: 鍵はすべて表サイズの倍数なので、k mod m はどれも同じスロットを返す。連鎖法は全部を保持するが、たった一本の鎖に。
探索規則: O(n)
計算例: 鍵 0, 8, 16, 24, 32, 40 を m = 8 に入れる → すべてスロット 0 へ。挿入の総コストは 1+2+3+4+5+6 = 21 回、平均 3.50
この型を開く: 全て衝突03
わかっていること: 鎖は作らない。衝突したら空きが見つかるまで一つずつ先へ進む。すべての要素は表の中に収まる。
探索規則: (h + i) mod m
計算例: 鍵 3, 11, 19, 6, 14, 22 を m = 8 に入れる → スロット 3, 4, 5, 6, 7, 0、探索回数は 1, 2, 3, 1, 2, 3。平均 2.00 で、六つは切れ目のない一続きになる
この型を開く: 線形探査法04
わかっていること: 衝突したら i ではなく i² スロット分だけ飛ぶ。塊は崩れるが、探索の列はもうすべてのスロットを訪れない。
探索規則: (h + i2) mod m
計算例: 同じ鍵を m = 8 に入れる → 3, 4, 7, 6, 2、そして 22 は完全に失敗する。m が 2 の冪だと i² mod 8 は 0, 1, 4 しか取らず、届くのは三つのスロットだけ
この型を開く: 二次探査法テーブルの使用率は75%で、検索1回あたりの探査回数は平均3.5回である。線形探査の標準公式では、その負荷率において2.5回と予測される。どちらが誤っているのかを突き止めよ。
どちらも誤ってはおらず、その理由はキーにある。6つのキーそれぞれをテーブル固有の関数でハッシュ化すると、いずれも3を返す。これらは公差8の等差数列であり、テーブルにはちょうど8つのスロットが存在する。
負荷率は確かに0.75のままである(8つのスロットに6つのキー)。それは単に、キーがどこに入ったかについて何も語っていないだけである。
したがって、探査列は考えられうる最悪のものとなる。1つ目のキーは空きスロットに入り、2つ目のキーは1スロット進み、3つ目のキーは2スロット進む。6つのキー全体で 1 + 2 + … + 6 = 21 回の探査を要し、そのうち 15 回がパネルの報告する余分な作業である。
これは検索1回あたり平均 3.5 回の探査となる。
教科書の見積もりはキーが一様に分散することを前提としており、α = 0.75 では 2.5 となる。2.5 と 3.5 の差は誤差ではない。テーブルサイズと共通の因数を持つハッシュ関数を、同じく共通の因数を持つキー群に適用したことで生じるコストである。
解答
ツールには α = 0.75、余分な作業として 15 回の探査、そして平均 3.5 回が表示される。ここからの教訓は、負荷率は有名な数値であるものの、それ単独で注視すべきではないということである。ここでの値は、良く分散された6つのキーを保持するテーブル(その場合のコストは 2.5)と全く同じである。変化したのは、キーの集合と法(モジュラス)との相互作用である。これこそがテーブルサイズに素数が選ばれる理由であり、構造体をたまたま容量の倍数になっているフィールドでハッシュ化すると、すべての指標が健全に見えるにもかかわらず O(1) が O(n) に悪化する理由である。サイズを 8 から 7 に変更すれば、平均値が激減することが確認できる。
パネルは 8 個のスロットに 6 個のキーを入れ、占有率 0.75、探索回数 3.5 と報告します。この占有率での成功探索はおよそ 2.5 回——余裕があります。ではなぜ、現実のハッシュマップはどれも満杯にせず、ちょうど 0.75 でリサイズするのでしょうか。
パネルの状態から始めます。4 分の 3 が埋まっていて、メモリの使い方としては妥当に聞こえます。
成功探索は安心できる数です。目当てのキーが見つかるまでに、平均しておよそ 2.5 個のスロットを調べるだけ。
失敗探索は別の式に従い、その違いに答えのすべてがあります。失敗は「無い」ことを示すために、埋まったスロットの連なりを端まで歩き切らねばならない——だから空き具合の項が線形ではなく 2 乗で効きます。
占有率を少し上げて、2 乗が何をするか読み取ってください。0.75 から 0.90 は、埋まり具合の変化としては控えめに聞こえます。
同じ一歩に対する 2 つの増え方を比べます。ヒットの費用は 2 倍を少し超える程度、ミスの費用は 6 倍近くになります。
だからテーブルは代わりに倍化します。全キーを再ハッシュするので m 回の操作がかかりますが、次にそれが起きるまでに m 回の挿入を買えます。
解答
ミスは 0.75 で 8.5 回、0.90 で 50.5 回、0.95 では 200.5 回かかります。標準ライブラリが軒並み 0.75 をリサイズのしきい値にしているのはこのためで、メモリと速度の折衷というより、崖の手前の最後の一点だからです。そして効いてくるのはミスのほうです。挿入はまずミスから始まり、見つからない探索はミスだけでできているからです。安心できる 2.5 が語っているのは、そもそも心配していなかった場合のことです。
学習の道すじ