植物 植物
直前対策講座:ハッシュ法によるテーブル登録

AOBA's Information Processing Education



1998/07/05

注意1:このページは、回線を切断した後でゆっくりご覧になってください(テキストを印刷する場合は、その取り扱いに注意してください)。

注意2:背景が白地の画面を長時間見つめていると頭が痛くなってしまいますので、ここは背景をグレーにしています。


「平成8年第2種 春期 午後 問1」

問1 次の流れ図の説明及び流れ図を読んで、設問に答えよ。

[流れ図の説明]
 配列A(1)〜A(n)に格納されている正の整数データを、ハッシュ法を用いてテーブルに登録する処理の流れ図である。
 ハッシュ法は、表の探索及び表へのエントリの登録,更新を効率よく行う際などに用いられる手法の一つである。この手法はハッシュ関数と呼ぶ計算式を用いて、対象データを限定された範囲の値(ハッシュ値)に変換し、この値を利用してテーブル上の格納位置を決定する。ここではハッシュ関数として、次の式を用いる。

 ハッシュ値=整数データを15で割った余り+1

 ハッシュ法の特徴は、異なるデータのハッシュ値が等しくなる場合がある(これを衝突という)ことである。この流れ図では、衝突が生じた場合の解決方法として、ハッシュ値が等しいデータ同士をチェーンでつなぐ方式を用いている。

 テーブルは図に示すように、整数データ(data)とチェーン(chn)の二つの要素からなるレコードの配列で構成されている。テーブルの先頭15レコード(添字の値が1から15まで)は、ハッシュ値が各添字の値に等しい最初の整数データを格納するための領域である。添字が16以降のレコードは、ハッシュ値が等しい2個目以降の後続データを発生した順に格納するための領域である。
 テーブル(data及びchn)の初期値として、すべての要素に0を格納しておく。ハッシュ値の等しいデータがある場合には、後続データを格納した場所の添字の値をチェーンに格納する。
 例えば、図は配列Aに格納されている四つの整数データ(75,100,253,355)を順にテーブルへ登録した状態を示すものである。整数データ100及び355はハッシュ値が11で同じ値となり、整数データ100のレコードのチェーンには整数データ355のレコードの添字の値16が格納されている。

図1

図2

設問 流れ図中の(  )に入れる正しい答えを、解答群の中から選べ。

aに関する解答群
 ア 0   イ 1   ウ 15   エ 16  オ n

b,cに関する解答群
 ア data(hash) イ data( j ) ウ data( k ) エ chn(hash)
 オ chn( j ) カ chn( k ) キ  ク hash


解説

 今週はハッシュ法(によるテーブル登録)に関する問題というよりも、リスト要素の追加に関する問題と考えた方がいいでしょう。だけどせっかくですので、ここでハッシュ法について簡単に触れておきます。
 ハッシュ法とは、アクセスする要素をハッシュ関数(問題にあるように、余りをとる関数が一般的)により変換し、変換した値からアクセスする位置を見つける探索手法です。
 データを登録する際、求めたハッシュ値(ハッシュ関数の値)の位置にすでにデータが格納されている状態のことを、衝突(コリジョン)といいます。またこのとき、先に格納されているデータ(問題では100)をホームデータ,後に格納しようとしたデータ(問題では355)をシノニムデータといいます。
 衝突が発生した場合に備えた対処法としては、チェーン法(オープンハッシュ法)オープンアドレス法(クローズドハッシュ法)があります。今週の流れ図の処理は、チェーン法によって衝突に備えていました。
 ちなみにオープンアドレス法は、衝突が発生した時、テーブル(ハッシュ表)に空いてる位置が見つかるまで、再ハッシュを行う方式です。

 さて問題の解説です。
 流れ図の処理はチェーン法によって衝突に備えていました。チェーン法は、同じハッシュ値のデータをリスト構造によって表現する方式です。以下の図を参照してください(四角中の斜め線はリストの終わりを意味する)。

図3

 データ100,355,55は同じハッシュ値11を持ちます。そこで、最初の100から355にポイントし、さらに355から55にポイントします。
 問題ではこのリスト構造を、配列を用いて表現していました。

bについて
 aを解答するにはjの意味を把握しなければなりませんが、jは流れ図の後半で出てきますので後回しにしましょう。
 空欄bの処理に流れるのは、data(hash)=0の時です。data(hash)の値が0になるのは、今回テーブルに登録するA(i)と同じハッシュ値のデータが、まだテーブルに登録されていないことを意味します(テーブルに登録するA(1)〜A(n)の値は正の整数だから...登録されていれば絶対に0にならない)。
 つまり、data(hash)の領域が空いているのですから、そのままその位置にA(i)を格納すればよいでしょう。

aについて
 空欄cの処理に流れるのは、今回テーブルに登録するA(i)と同じハッシュ値のデータが、すでにテーブルに登録されている時です(bの解説の逆です)。
 A(i)と同じハッシュ値のデータがすでにテーブルに登録されている場合は、A(i)は添字が16以降の要素に格納しなければなりません(問題文より)。
 探索ループの1つ後に、”A(i)→data(j)”の処理がありますので、「格納する要素の添字はjである」と分かります。
 さらに、探索ループの2つ後に、”j+1→j”の処理が見えます。
 するとjは増加する方向に進むのですから、jの初期値としては”採りうる最も小さい値”で初期化する必要があります。よって求める答えは16です。

cについて
 リストに新たな要素を追加する場合、追加する要素の1つ手前の要素のポインタ(次にチェーンするためのデータ)を更新する必要があります(ポインタは本問題におけるchnの値です)。
 例えば、上図でデータ55の後にデータ85を追加するとすれば、追加前の55のポインタは0(リストの終わり)ですが、これを85へのポインタに更新する必要があります。
 結論から言えば、本問題で衝突が発生した場合もこの処理を行わなければなりません。これが”j→( c )”の処理です。
 ”探索”ループ中の”chn(hash)→hash”では、リストの要素を1つづつ進める処理を行います。この処理を行った結果hashが0になった時に”探索”ループを脱出していますが、hashが0になるのは、リストの末尾まで達した時です(添字は1から始まるので、チェーンがあれば絶対に0にならない)。
 また”chn(hash)→hash”の前に”hash→k”の処理がありますので、kはhashが指す要素の一つ手前の要素の添字になっています。
 以上を総合して、空欄cは、今回格納した要素の一つ手前の要素のポインタ部分つまりchn(k)を、今回格納した要素の添字つまりjで更新する処理が入ります。

 今週は以上です。
 ではまた来週。


解答

a−エ  b−ア  c−カ