ハッシュ表探索|格納位置を計算で決める・衝突したら次の番号へ【基本情報技術者試験 科目B】

基本情報技術者試験

現行FE シラバス Ver9.2 準拠擬似言語の記述形式は2022年から変更なし最終更新 2026-10-11

ハッシュ表探索は、値から格納位置を計算して、その場所を見に行く探し方です。前から1つずつ照らし合わせる線形探索とちがい、最初に見る場所が、計算で決まります。

期間限定クーポンPR|Udemy の講座科目B オリジナル模試 3回分・60問42%OFF 1,500円2,600円中身を見る ›

格納位置を、値から計算する

要素数が 5 の配列 tana に、正の整数を入れていきます。IPAが公開している科目Bの問題と同じく、配列の要素番号は 1 から始まるものとします。はじめは5つとも -1 にしておきます。-1 は「まだ何も入っていない」の印です。入れる値は正の整数だけなので、印と値を取りちがえることはありません。

どの要素番号に入れるかは、入れる値そのものから計算します。

格納位置の決め方

(値 mod 5) + 1

値 mod 5値を 5 で割った余り。0・1・2・3・4 のどれかになる

+ 1要素番号は 1 から始まるので、1 を足して 1〜5 にする

13 と 20 を、この順に入れます。

値から番号を計算して、その番号に入れる

枡の上の数字=要素番号 / -1=まだ何も入っていない印 / 緑=いま入れた枡

13 を入れる (13 mod 5) + 1 = 3 + 1 = 4

1-1

2-1

3-1

413

5-1

13 を 5 で割ると、2 あまり 3。余りの 3 に 1 を足して 4番

20 を入れる (20 mod 5) + 1 = 0 + 1 = 1

120

2-1

3-1

413

5-1

20 は 5 で割り切れるので、余りは 0。1 を足して 1番

どちらも、計算した番号が空いていたので、そのまま入った

値を入れておくこの配列をハッシュ表、格納位置を計算する式をハッシュ関数、計算で出た値(ここでは要素番号)をハッシュ値といいます。

探すときも、同じ計算をします。13 を探すなら (13 mod 5) + 1 = 4。4番を見ると、13 があります。入れるときと同じ式で番号を出すので、入れた場所をそのまま見に行けます。前から順に 1番、2番と見ていく必要がありません。

衝突 ── 同じ番号になったら、次の番号へ

続けて 18 を入れます。(18 mod 5) + 1 = 3 + 1 = 4。13 を入れた番号と同じです。このように、別の値なのに同じ番号になることを衝突といいます。

4番に 18 を書くと 13 が消えてしまいます。そこで、ふさがっていたら次の番号を見ると決めておきます。次もふさがっていたら、さらに次へ。空きが見つかるまで続けます。

次の番号の決め方

(いまの番号 mod 5) + 1

4番の次(4 mod 5) + 1 = 4 + 1 = 5(4 を 5 で割ると 0 あまり 4)

5番の次(5 mod 5) + 1 = 0 + 1 = 1(5 は 5 で割り切れるので余りは 0)

ただ 1 を足すだけだと、5番の次が 6番になります。6番の要素はありません。mod をはさむと、5番の次が 1番に戻ります。

18 を入れる ── 4番がふさがっているので、次の番号へ

枡の上の数字=要素番号 / -1=まだ何も入っていない印 / ▲=いま見ている枡 / 橙=値が入っていた枡 / 緑の破線=これから入れる枡 / 緑=いま入れた枡

① 番号を計算する (18 mod 5) + 1 = 3 + 1 = 4

120

2-1

3-1

413▲

5-1

4番には 13 が入っている。-1 ではないので、ここには入れられない

② 次の番号を見る (4 mod 5) + 1 = 4 + 1 = 5

120

2-1

3-1

413

5-1▲

5番は -1 で空いているので、ここに入れる

③ 5番に入れる

120

2-1

3-1

413

518

13 は4番に残ったまま。18 は、計算した4番の1つ先に入った

入れるプログラムを、上から読む

ここまで手でやったことを、プログラムにします。ireru が値を1つ入れる手続、junbi が 13・20・18 を順に入れる手続です。

大域: 整数型の配列: tana

○ireru(整数型: atai)
  整数型: i ← (atai mod tanaの要素数) + 1
  while (tana[i] ≠ -1)
    i ← (i mod tanaの要素数) + 1
  endwhile
  tana[i] ← atai

○junbi()
  tana ← {5個の -1}
  ireru(13)
  ireru(20)
  ireru(18)

当サイトで作った例です。

junbi の1行目 tana ← {5個の -1} は、5つの要素をすべて -1 にする書き方です。junbi を呼び出すと、tana は {20, -1, -1, 13, 18} になります。図で見た並びと同じです。

上から読む

  1. 大域: 整数型の配列: tana
    ハッシュ表。大域: が付いた配列は、どの手続・関数からも同じ1つが見えます(大域変数と局所変数)。ireru が書き込んだ値は、次に呼ばれたときも残っています。
  2.   整数型: i ← (atai mod tanaの要素数) + 1
    ハッシュ値を計算する。tanaの要素数 は 5 です。i が、いま見ている要素番号になります。
  3.   while (tana[i] ≠ -1)
        i ← (i mod tanaの要素数) + 1
      endwhile
    ふさがっているあいだ、次の番号へ。tana[i] が -1 でなければ、そこには値が入っています。13 と 20 のときは最初から空いているので、中を1回も実行しません。18 のときは1回実行して、i が 4 から 5 に変わります。
  4.   tana[i] ← atai
    空いている場所に入れる。while を抜けてここに来たとき、tana[i] は必ず -1 です。
空きが残っていることが前提

5つとも埋まった状態で ireru を呼び出すと、空きが見つからないので while が終わりません。この例は、空きが残るように、入れる値を3つにしています。このあとの探すプログラムも、入っていない値を探すときは空きに当たって止まるので、空きが残っていることが前提です。

探す ── 入れたときと同じ順にたどる

探す関数 sagasu です。見つかったらその要素番号を、無ければ -1 を返します(要素番号は 1 からなので、-1 は番号としてありえない値です)。tana は入れるプログラムと同じ大域の配列で、3つの値を入れ終えた {20, -1, -1, 13, 18} になっているとします。

○整数型: sagasu(整数型: atai)
  整数型: i ← (atai mod tanaの要素数) + 1
  while (tana[i] ≠ -1)
    if (tana[i] = atai)
      return i
    endif
    i ← (i mod tanaの要素数) + 1
  endwhile
  return -1

当サイトで作った例です。

最初の番号の出し方も、次の番号への進み方も、ireru と同じです。ちがうのは2か所です。進む前に if で探している値かどうかを確かめ、同じなら return i でその番号を返して終わります。空きに当たって while を抜けたときは、値を入れる代わりに return -1 で「無い」と答えます。

衝突して5番に入った 18 を探します。sagasu(18) が返すのは 5 です。

18 を探す ── 入れたときと同じ 4番 → 5番 の順に見る

枡の上の数字=要素番号 / -1=まだ何も入っていない印 / ▲=いま見ている枡(赤=探している値とちがう・緑=同じ)

① 番号を計算する (18 mod 5) + 1 = 3 + 1 = 4

120

2-1

3-1

413▲

518

4番は 13。18 ではないので、次の番号へ

② 次の番号を見る (4 mod 5) + 1 = 4 + 1 = 5

120

2-1

3-1

413

518▲

5番は 18。見つかったので、5 を返して終わる

見たのは4番と5番だけ。1番・2番・3番は見ていない

18 は 4番 → 5番 と進んで入ったので、同じ 4番 → 5番 と進めば必ず出会います。

無い値を探すと、空きで止まる

入れていない 23 を探すと、どこでやめるのでしょうか。sagasu(23) を1行ずつ動かします。5番の次が 1番に戻るところも出てきます。

sagasu(23) を1行ずつ動かす

当サイトオリジナルの例題


ループ開始前

ハッシュ表(3つの値を入れ終えたところ)

▲ いま読んでいる

いま計算していること

まだ計算していません

変数の状態

トレース表(進めると1行ずつ積み上がります)

空きに当たったら「無い」と言い切れるのは、もし 23 を入れていたなら、入れるときも同じ 4番 → 5番 → 1番 → 2番 と進み、空いている2番に入れたはずだからです。この例は 5つのうち 3つが埋まっているので 4か所を見ましたが、空きが多い表ほど、早く空きに当たって止まります。

出題では ── ふさがっていたときの決まりを読む

本物もこう書かれる

(令和5年度 基本情報技術者試験 科目B 公開問題 問4)正の整数 value を、大域の配列 hashArray に入れる問題です。格納位置は、ハッシュ関数 calcHash1 が次の式で計算して返します。

  return (value mod hashArrayの要素数) + 1

ここまで使ってきた (値 mod 要素数) + 1 と同じ形です。空きの印も、同じ -1 が使われています。

ちがうのは、ふさがっていたときです。この問題は次の番号へ進みません。2つ目の関数 calcHash2 の式で、もう一度だけ番号を計算し直し、そこもふさがっていたら、入れずに false を返します。

読む場所は2つ

ふさがっていたときにどうするかは、プログラムに書いてあります。自分で決めるものではありません。

①ハッシュ値を計算している式(最初に番号を出す行)

②そこがふさがっていたときに実行される行

この問題を最後まで解く手順は、令和5年度 科目B 問4の解説にあります。

つまずきポイントまとめ

まちがえ方 正しい読み方
余りをそのまま要素番号にする 余りは 0 から。1 を足して 1 からの番号にする
ふさがっていたら上書きする 先に入っていた値はそのまま。あとから来た値が別の番号へ行く
計算した番号に無ければ「無い」と答える 衝突して先の番号に入っていることがある。見つかるか、空きに当たるまで進む

次に読む

A8-1 再帰とは ─ 自分を呼ぶ関数と、終了条件
解説 令和5年度 科目B 問4 ─ ハッシュ表に3つの値を入れる
A2-3 探す(線形探索)─ 前から1つずつ照らし合わせる
第2部 科目Bのアルゴリズム ─ 出るものの地図
目次 基本情報技術者試験 科目B 攻略ガイド

この記事で引用した資料

いずれも独立行政法人情報処理推進機構(IPA)が公表したものです。IPAは公表済みの試験問題について、教育目的での使用に許諾および使用料を不要としていますが、著作権は放棄していません。本記事では、引用した箇所の文言を改変していません(省略や補いがある場合は、その場に明記しています)。

本文の例題は当サイトのオリジナルです。

タイトルとURLをコピーしました