Index |
|||||||||
C++の壺・ハッシュ篇
C++の基本テクニックのTipsです。ハッシュとは、データを数値に変換する手法で、データ検証やデータ検索に利用されます。ハッシュ篇では、データ検索におけるハッシュ法の基本的な用法を扱います。ハッシュを利用すると、大量のデータを高速で検索することが可能となります。
sasaraan programming ![]() Exposition ●ハッシュ関数 ハッシュ関数とは、可変長のデータから固定長のデータを求める関数です。データ検索では、主に、文字列(キー)を一定範囲の数値(ハッシュ値)に変換する関数を指します。この場合、ハッシュ値は、配列の添え字(インデックス)に利用されます。ハッシュ関数は、同じキーからは常に同じハッシュ値を返す必要があります。また、ハッシュ値に偏りがなく、ある程度はばらつくことが求められます。通常は、素数を掛けたり割ったりすることで分布をばらつかせる演出が行われます。 下例は、文字コードを足していくだけの単純なものです。この中で、引数 mod は用意する配列の要素数です。通常はばらつきを確保するために素数が用いられます。これにより、 0以上 要素数未満( = 最大添え字以下)の整数値を求めることができ、直接配列の添え字として利用することが可能となります。 このようなハッシュ関数には様々な定義の仕方があり、実際にはデータの量や性質により内容を設計していく必要があります。例えば、キー文字列が数百文字に及ぶ可能性がある時は、下記のハッシュ関数は向いていません。
●ハッシュテーブル ハッシュ関数によって管理されるデータの体系をハッシュテーブルと呼びます。そのおおもとは通常の配列と変わりがありません。ハッシュ関数によって得られた整数値を配列の添え字と解し、データを配列要素として組み込みます。この要素数は、データをばらつかせるため、素数が望ましいとされています。また、各データはキーと値の両方を保持する必要があり、構造体やクラスが利用されます。ただし、異なる文字列(キー)でも同じハッシュ値を生成することが考えられます。前節の main 関数で、同じハッシュ値 4 を生成する "Sisley" と "Chagall" は衝突しています。この時はどちらかのデータを捨てるか、さらにデータを配列化して両方とも取り入れるか、いずれかの選択が必要です。本ページでは、各データを自己参照構造体にして、リスト構造を利用してデータを繋いでいく例(詳しくはリスト篇を参照してください)を次節に挙げています。この方法はチェイン法と呼ばれ、不定数量のデータが衝突しても安全にテーブルに格納することが可能です。 // 自己参照構造体の例 この図からも分る通り、ハッシュテーブルでは、使われない要素の分もメモリを占有します。また、各データにはキー文字列やポインタも格納します。ハッシュテーブルは、高速検索を実現するためにメモリを大量に消費する性格を持ちますので、メモリ管理にも気を配る必要があります。このため、多くの場合、new / delete、malloc / free などを使ってデータやテーブルを動的に作成・破棄する方法が採られます。 ●データ処理
リスト構造を利用したハッシュテーブルのサンプルを以下に掲げておきます。データの登録では、既存のキーを調べ、あれば値の上書きを行っています。この時、データは、先入れ方式での登録(先頭に挿入)となります。また、データは new 演算子で動的に作成していますので、使い終わった後は delete 演算子で削除しています。
この程度のデータ数では効果は希薄ですが、サンプルのハッシュ関数では、値に素数31 を掛けながらハッシュ値を算出して、よりばらけるようにしています。実際には莫大な量のデータを扱うことが多いので、さらに複雑で柔軟なハッシュ関数やデータ操作が求められます。
|
|||||||||
www.sasaraan.net |
(c) morijoh |