1 / 6

2005 年度 データ構造とアルゴリズム 第 6 回 「ハッシュ法を用いた探索」

2005 年度 データ構造とアルゴリズム 第 6 回 「ハッシュ法を用いた探索」. 西尾 信彦 nishio@cs.ritsumei.ac.jp 立命館大学情報理工学部 情報システム学科. O(log n) よりも高速な探索. 配列のインデックスとキーを一致させれば O(1) である!!! キーの範囲だけの大きさの配列が必要 非実用的 キーから配列のインデックスに変換する適切な関数を作成,これをハッシュ関数という 均等に分配するような関数 キーを 100 で割れば大きさは 100 分の 1 になる 同じハッシュ値となるレコードは同じハッシュバケットに入る.

suchin
Download Presentation

2005 年度 データ構造とアルゴリズム 第 6 回 「ハッシュ法を用いた探索」

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 2005年度データ構造とアルゴリズム第6回「ハッシュ法を用いた探索」2005年度データ構造とアルゴリズム第6回「ハッシュ法を用いた探索」 西尾 信彦 nishio@cs.ritsumei.ac.jp 立命館大学情報理工学部 情報システム学科

  2. O(log n)よりも高速な探索 • 配列のインデックスとキーを一致させればO(1)である!!! • キーの範囲だけの大きさの配列が必要 • 非実用的 • キーから配列のインデックスに変換する適切な関数を作成,これをハッシュ関数という • 均等に分配するような関数 • キーを100で割れば大きさは100分の1になる • 同じハッシュ値となるレコードは同じハッシュバケットに入る

  3. ハッシュ関数 • キーのとりうる範囲を一定の範囲(0~M-1)する • ハッシュの衝突は極力避けたい • 均等に分散させるため • 例えば,整数のキーであれば剰余系を利用する • 文字列によるキーの場合 • 頭の数文字で生成するのはダメ • 同じ文字セットの順番が変っていたら違うハッシュ値が欲しい • KnuthやWeinbergの例を参照 • ハッシュ関数自体のコストがかかっていたらそもそもダメ

  4. 分離連鎖法 • ハッシュ値の衝突を許容し • ハッシュバケットをリストで生成する • 各ハッシュ値のリストの先頭からなる配列を用意する • ハッシュ関数でバケットを選択して,リストを逐次検索 • 計算の手間はN/M? • 適切なMの選び方 • バケットを構成するリストを工夫する

  5. Hash 分離連鎖法の例: 実行結果: bucket[0] Jamaica bucket[0] France bucket[0] China . . . bucket[12] Belguim bucket[12] Argentina 検索ワード:Japan Japan が見つかりました. 入力ファイル #include <stdio.h> #include <stdlib.h> #include <string.h> #define HASHSIZE 13 #define STR_MAX 256 typedef struct _listelem{ struct _listelem *next; char *s; }listelem, *list; list bucket[HASHSIZE]; char *word; unsigned long hashpjw(unsigned char* str){ unsigned long hash = 0, g; for( ; *str; ++str){ hash = (hash << 4) + *str; if((g = hash & 0xf0000000)){ hash ^= g >> 24; hash ^= g; } } return hash; } Afghanistan Albania Algeria Andorra Angola . . . . Kenya Kiribati Korea 上図のような入力ファイルを用いて,データ入力を行い,キーボードから検索キーを入力し,リストにあるかどうかを調べる

  6. Hash 分離連鎖法の例: char *search_add(char *s, int flag){ int h; list l; h = hashpjw(s) % HASHSIZE; /* ハッシュ値を算出 */ for(l = bucket[h]; l; l = l->next){ if(strcmp(l->s, s) == 0) return l->s; } if(flag == 0) return NULL; l = (list)malloc(sizeof(listelem)); l->s = s; l->next = bucket[h]; bucket[h] = l; return l->s; } void RegistryList(char *filename){ FILE *fpIn; char str[STR_MAX], tmp[STR_MAX]; int i, start; if((fpIn = fopen(filename, "r")) == NULL){ fprintf(stderr, "Cannot open file [%s].\n", filename); exit(1); } while(fgets(str, STR_MAX, fpIn) != NULL){ sscanf(str, "%s", tmp); word = (char *)malloc(sizeof(char)*strlen(tmp)); strcpy(word, tmp); /* リストへの登録を行うので,第二引数を0以外にしておく */ search_add(word, 1); } fclose(fpIn); } int main(int argc, char **argv){ int i; list p; char input[STR_MAX]; /* ファイルから読み込んだデータをリストに格納 */ RegistryList(argv[1]); for(i = 0; i < HASHSIZE ; i++){ for(p = bucket[i]; p != NULL ; p = p->next){ printf("bucket[%d] %s\n", i, p->s); } } printf("検索ワード:"); scanf("%s", input); /* 検索のみなので,第二引数のflagを0にする */ if(search_add(input, 0) != NULL){ printf("%s が見つかりました.\n", input); } else{ printf("%s は見つかりませんでした.\n", input); } }

More Related