サイトマップ / 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言語講座−それ自体コンパイルできる教材を使った講座です−

青い直線

サイトマップ / C言語講座出入り口総目次目次:ヒープ領域>ハッシュテーブル