サイトマップ / C言語講座>出入り口>総目次>目次:ヒープ領域>ハッシュテーブル
[リスト型のデータ構造]←このソース→[双方向リスト]
/* 今日はハッシュテーブルについて学びます。ハッシュ値とは、あるキーワードからある変換規則によって、得られる整数値のことです。
ポインタの配列を用意しておいて、キーワードへのポインタを、ハッシュ値を添字にして、配列に保存します。このポインタの配列のことをハッシュテーブルといいます。キーワードをハッシュテーブルに保存することにより、効率よく取り出すことができます。そのキーワードが既に登録済みかどうかは、キーワードからハッシュ値を割り出し、ハッシュテーブルを調べれば、瞬時にわかります。
二つ以上のキーワードのハッシュ値が、たまたま一致してしまうことがあります。これをハッシュの衝突といいます。衝突した場合の解決法は幾つかあります。今回は、リスト型のデータ構造にして、衝突した場合は先に登録されているキーワードの後ろに、データを追加します。 */
/* 今回は、幾つかのCの予約語をハッシュテーブルに登録して、メインルーチンから、キーワードを入力して、登録済みかどうか調べます。下記の構造体を使い、リスト型のデータ構造を実現します。
struct list {
char keyword[MAX_KW_LEN];
struct list *next;
};
下記にハッシュテーブルを示します。大きさがHASHSIZE の list * 型のポインタの配列です。この配列は複数の関数から参照されるので、静的領域に置きます。
struct list *hashtable[HASHSIZE];
下記にキーワードをハッシュ値に変換する関数を示します。ここでは、キーワードの各文字の値を合計して、HASHSIZE で割った余りを返しています。戻り値は 0 から HASHSIZE - 1 の範囲です。
int Hash(char *key)
{
int hashval = 0;
while (*key != '\0')
hashval += *key++;
return (hashval % HASHSIZE);
}
その他の関数として、下記のものがありますが、ソースプログラム中に詳しいコメントを付けておいたので、そちらをご覧下さい。
ハッシュテーブルにキーワードを登録
void InitHTable(void)
キーワードがハッシュテーブルに登録済みか調べる
int FindKeyWord(char *key);
ハッシュテーブルをもとに、ハッシュ値とキーワードを一覧表示
void ListKeyWord(void);
malloc( ) で割り付けたメモリを解放
void FreeKeyWord(void);
*/
#include <stdio.h>
#include <stdlib.h> /* exit( ) free( ) malloc( ) に必要 */
#include <string.h> /* strcpy( ) strcmp( ) に必要 */
#define HASHSIZE 40 /* ハッシュテーブルの大きさ */
#define MAX_KW_LEN 256 /* キーワードの最大の長さ */
#define NUM_KW 23 /* キーワードの数 */
#define TRUE 1
#define FALSE 0
struct list {
char keyword[MAX_KW_LEN];
struct list *next; /* 次の list へのポインタ */
};
struct list *hashtable[HASHSIZE]; /* ハッシュテーブル */
/* キーワード ( Cの予約語 ) */
static char kw[NUM_KW][MAX_KW_LEN] = {
"auto", "break", "double",
"enum", "char", "continue", "extern", "float", "for", "int",
"long", "register", "short", "signed", "static",
"struct", "typedef", "union", "unsigned", "return",
"void", "volatile", "while"
};
int Hash(char *key); /* 0 から HASHSIZE のハッシュ値を返す */
void InitHTable(void); /* キーワードをハッシュテーブルに登録 */
int FindKeyWord(char *key); /* ハッシュテーブルに登録済みか調べる */
void ListKeyWord(void); /* ハッシュ値とキーワードを一覧表示 */
void FreeKeyWord(void); /* malloc( ) で割り付けたメモリを解放 */
void main(void);
/* 0 から HASHSIZE - 1 のハッシュ値を返す */
int Hash(char *key)
{
int hashval = 0;
while (*key != '\0')
hashval += *key++;
return (hashval % HASHSIZE);
}
/* キーワードをハッシュテーブルに登録 */
void InitHTable(void)
{
int i;
struct list *p, *q;
int hashval;
for (i = 0; i < NUM_KW; i++) {
if ((FindKeyWord(kw[i])) == FALSE) { /* 登録されていなかったら */
/* メモリを割り付ける */
if ((p = (struct list *)malloc(sizeof(struct list))) == NULL) {
fprintf(stderr, "メモリ不足です。\n");
exit(2);
}
strcpy((*p).keyword, kw[i]);
hashval = Hash(kw[i]); /* ハッシュ値を求めて */
if (hashtable[hashval] == NULL) { /* 未登録なら */
hashtable[hashval] = p; /* p の指すアドレスを登録 */
p->next = NULL; /* リストの末尾に NULL を追加 */
}
else { /* 既に登録していたら */
q = hashtable[hashval];
while (q->next != NULL) /* データがなくなるまで */
q = q->next; /* リストをたどる */
q->next = p; /* リストの末尾に p の指すアドレスを登録 */
p->next = NULL; /* その末尾に NULL を追加 */
}
}
}
}
/* ハッシュテーブルに登録済みか調べる */
int FindKeyWord(char *key)
{
struct list *p;
for (p = hashtable[Hash(key)]; p != NULL; p = p->next)
if (!strcmp(key, (*p).keyword)) /* 登録済みなら */
return (TRUE); /* TRUE を返す */
return (FALSE); /* 未登録ならFALSE を返す */
}
/* ハッシュ値とキーワードを一覧表示 */
void ListKeyWord(void)
{
int i;
struct list *p;
for (i = 0; i < HASHSIZE; i++)
for (p = hashtable[i]; p != NULL; p = p->next) /* p が NULL でなければ */
/* ハッシュ値とキーワードを表示 */
printf("予約語:%s ハッシュ値:%d:\n", (*p).keyword, Hash((*p).keyword));
}
/* malloc( ) で割り付けたメモリを解放 */
void FreeKeyWord(void)
{
int i;
struct list *p, *q;
for (i = 0; i < HASHSIZE; i++)
for (p = hashtable[i]; p != NULL; ) { /* p が NULL でなければ */
q = p->next; /* p->next を保存 */
free(p); /* メモリを解放 */
p = q; /* p->next を p に代入 */
}
}
void main(void)
{
char word[MAX_KW_LEN];
int i;
InitHTable( );
ListKeyWord( );
for (i = 0; i < 4; i++) {
printf("Cの予約語を入力して下さい ");
gets(word);
if ((FindKeyWord(word)) == TRUE)
printf("%s は登録済みです。\n", word);
else
printf("%s は未登録です。\n", word);
}
FreeKeyWord( );
}
|
[リスト型のデータ構造]←このソース→[双方向リスト]
/* (C) 2000- YFプロ. All Rights Reserved. */ 提供:C言語講座−それ自体コンパイルできる教材を使った講座です−