2分木なども終わって、検索処理のさらなる高速化として、 ハッシュ法を説明する。
オープンアドレス法
電話番号が記録されているのかどうかを探す処理を考えると、 最も単純な方法は、電話番号を配列の添字にする方法となる。
int array[ 1000000 ] ; // 局番2桁+4桁
void entry( int phone ) {
array[ phone ] = phone ;
}
int search( int phone ) {
if ( array[ phone ] == 0 )
return 0 ;
else
return 1 ;
}
しかしこの方法では、0778621111 といった番号も考えると、 巨大なメモリを必要として、非現実的となる。 この際の解決法がハッシュ法で、データ件数が少なければ、 例えば電話番号の末尾2桁がおなじデータの発生する確率は低い。 もし、電話番号末尾2桁が同じでも、その番号の次の場所に保存するなどすればよい。
#define SIZE 100 // ハッシュ表のサイズ
int hash[ SIZE ] ; // ハッシュ表
int hash_func( int phone ) { // ハッシュ関数
return phone % SIZE ;
}
void entry( int phone ) {
int idx = hash_func( phone ) ;
while( hash[ idx ] != 0 ) // データ件数100で無限ループだけど...
idx = (idx + 1) % SIZE ;
hash[ idx ] = phone ;
}
int search( int phone ) {
int idx = hash_func( phone ) ;
while( hash[ idx ] != 0 ) {
if ( hash[ idx ] == phone )
return 1 ;
idx = (idx + 1) % SIZE ;
}
return 0 ;
}
チェイン法
オープンアドレス法では、次の空き場所を探して保存するが、 表サイズよりもデータ件数を多く保存することはできない。
表が埋まって、同じハッシュ値のデータがでてきたら、同じハッシュ値同士を リスト構造で保存する方法はチェイン法と呼ばれる。
struct List *hash[ SIZE ] ; // ポインタはNULLで全て初期化
void entry( int phone ) {
int idx = hash_func( phone ) ;
hash[ idx ] = cons( phone , hash[ idx ] ) ;
}
int search( int phone ) {
int idx = hash_func( phone ) ;
struct List* p ;
for( p = hash[ idx ] ;
p != NULL ;
p = p->next )
{
if ( p->data == phone )
return 1 ;
}
return 0 ;
}