ハッシュテーブル.

Slides:



Advertisements
Similar presentations
【事例演習5】  字句解析     解 説  “ハッシュを用いた字句解析の方法”.
Advertisements

プログラムのパタン演習 解説.
プログラミング言語としてのR 情報知能学科 白井 英俊.
第11回 整列 ~ シェルソート,クイックソート ~
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
第11回 整列 ~ バケットソート,基数ソート,ヒープソート~
ファーストイヤー・セミナーⅡ 第8回 データの入力.
データ構造とアルゴリズム 第10回 mallocとfree
基礎プログラミングおよび演習 第9回
プログラミング演習Ⅱ 第12回 文字列とポインタ(1)
データ構造とプログラミング技法 (第8回) ーデータの探索ー.
第10回 ソート(1):単純なソートアルゴリズム
情報工学概論 (アルゴリズムとデータ構造)
オペレーティングシステムJ/K 2004年11月4日
第8回 プログラミングⅡ 第8回
アルゴリズムとデータ構造 2011年6月13日
構造体.
岩井 儀雄 コンピュータ基礎演習  ー探索、整列ー 岩井 儀雄
第7章 データベース管理システム 7.1 データベース管理システムの概要 7.2 データベースの格納方式 7.3 問合せ処理.
エージェントを管理するボスの苦悩 問題 n人のエージェントを部下に持つボスがいる. エージェントは出張・帰還を頻繁に繰り返す.
データ構造と アルゴリズム 第八回 知能情報学部 新田直也.
ML 演習 第 7 回 新井淳也、中村宇佑、前田俊行 2011/05/31.
データ構造と アルゴリズム 第十一回 理工学部 情報システム工学科 新田直也.
第11回 整列 ~ シェルソート,クイックソート ~
第3回 配列,構造体,ポインタ ~ データ構造について学ぶための基礎~
第13回 ハッシュテーブルを使ったプログラム ~高速に検索するには?~.
二分探索木によるサーチ.
ハッシュ表 データ構造とプログラミング(12)
定兼邦彦 今井浩 東京大学理学系研究科 情報科学専攻
Cプログラミング演習 第7回 メモリ内でのデータの配置.
アルゴリズムとデータ構造1 2006年6月16日
プログラミング 4 記憶の割り付け.
アルゴリズムとデータ構造1 2005年7月15日
2005年度 データ構造とアルゴリズム 第3回 「C言語の復習:再帰的データ構造」
プログラミング入門2 第11回 情報工学科 篠埜 功.
第7回 プログラミングⅡ 第7回
第9回 優先度つき待ち行列,ヒープ,二分探索木
クイックソート.
P n ポインタの基礎 5 q m 5 7 int* p; int 型の変数を指すポインタ int* q; int 型の変数を指すポインタ int n=5, m=7; int 型の変数 int array[3]; int* pArray[3]; p = &n; ポインタにアドレスを代入しているのでOK.
データ構造と アルゴリズム 第五回 知能情報学部 新田直也.
Cプログラミング演習 第10回 二分探索木.
先進的計算基盤システムシンポジウム SACSIS2007併設企画 マルチコアプログラミングコンテスト 「Cellスピードチャレンジ2007」
プログラミング基礎B 文字列の扱い.
プログラミング 4 整列アルゴリズム.
2005年度 データ構造とアルゴリズム 第6回 「ハッシュ法を用いた探索」
プログラミング 4 探索と計算量.
プログラミング 4 木構造とヒープ.
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング言語論 第六回 理工学部 情報システム工学科 新田直也.
アルゴリズムとデータ構造1 2006年7月11日
15.cons と種々のデータ構造.
データ構造とアルゴリズム 第11回 リスト構造(1)
文字列へのポインタの配列 static char *lines[MAXLINES]; lines[0] NULL
データ構造とアルゴリズム (第5回) 静岡大学工学部 安藤和敏
第9回 優先度つき待ち行列,ヒープ,二分探索木
コンパイラ 2012年10月29日
アルゴリズムとデータ構造 2012年6月11日
アルゴリズムとプログラミング (Algorithms and Programming)
オペレーティングシステムJ/K (管理のためのデータ構造)
第11回放送授業.
アルゴリズムとデータ構造 補足資料11-3 「線形リストのオペレータ」
ネットワーク・プログラミング Cプログラミングの基礎.
プログラミング 4 文字列.
参考:大きい要素の処理.
2005年度 データ構造とアルゴリズム 第2回 「C言語の復習:配列」
新人研修発表 平成13年5月14日(月) 探索アルゴリズム ハッシュ法について 株式会社 エーアイネット・テクノロジ          須田 哲生.
情報処理Ⅱ 第2回 2004年10月12日(火).
アルゴリズムとデータ構造1 2007年7月6日
情報処理Ⅱ 小テスト 2005年2月1日(火).
計算機プログラミングI 第5回 2002年11月7日(木) 配列: 沢山のデータをまとめたデータ どんなものか どうやって使うのか
Presentation transcript:

ハッシュテーブル

探索アルゴリズム 表の中に入っているデータ(表の中のデータの個数をn個とする)の中から,目的のデータを探索するアルゴリズム 線形探索 表中のデータを1つ1つ順に端から調べるだけの単純な探索法 計算量は O(n) 二分探索,木 キー値の比較に基づき,途中で探索候補を絞っていくことによって,表全部を調べることなく高速化を図る 計算量は O(log n) ハッシュ法 平均してO(1)の計算量で探索,挿入,削除の全てを行うことができる

配列による探索 「キー値の範囲をおおうような配列」を使う方法 (例)レコード{学籍番号,名前,生年月日} キー値: 学籍番号(1から100までの値をとりうる) 1~100までの整数を添字とする配列を用意 (例)配列student[1]~student[100] に,それぞれレコードデータを入れる 配列を使って,キー値からレコードを取り出す方法: 与えられたキー値(この場合,学籍番号)を添字として,その配列を調べる 単純に考えて,「データが何個存在するかに関係なく,配列を1つ調べればいい」と考えれば,探索1回当りの計算量はO(1)

ハッシュ法 配列による探索 ハッシュ法 配列の添字として使用できるのは正の整数のみ キーの値が限られた範囲の整数である場合にしか使えない(一般的ではない) ハッシュ法 キーの値を直接配列の添字とするのではなく,キー値をある関数(ハッシュ関数)によって整数に変換して,この関数値を添字として配列を参照する キー値として,文字列など可能(名前による検索など) (例) 名前によって探索する場合 1.関数Hash に引数として,検索したい名前(文字列)を与える. 2.関数Hash は,与えられた文字列からなんらかの計算を行い,整数値を返す. 3.その整数値を配列の添字とする配列を参照する.

ハッシュ法 ハッシュ関数: ハッシュ値 ハッシュテーブル キー値を整数に変換する関数 常に,同じハッシュ関数を使うので,同じキーの値を与えた時,結果はいつも同じになる. → データを挿入する時も探索する時も配列の同じ場所を参照する ハッシュ値 ハッシュ関数の計算によって得られる整数値 ハッシュテーブル データが格納された配列 ハッシュ関数の計算,配列の参照にかかる時間は,データ数nに無関係で,O(1)の計算量

衝突 キーのとり得る値の種類に比べて,配列の添字として使える値の範囲は小さい 全てのキー値を,1対1で整数に変換することは不可能 配列の添字: 正の整数で,4バイトの整数 (0から2147483648) キーのとり得る値の種類の例: 4バイトの浮動小数なら: -3.4e38から3.4e38 全てのキー値を,1対1で整数に変換することは不可能 違うキーの値でも,ハッシュ値(ハッシュ関数を適用した結果)が同じになるということが起る. → このような事態を衝突と呼ぶ

衝突への対処法 連鎖法(チェイン法) 開放番地法 ハッシュ関数の値(ハッシュ値)が同じであるレコード同士をリストでつないでおく ハッシュテーブルには,リストを指すポインターを入れる 開放番地法 ハッシュテーブルそのものにレコードを入れる

連鎖法(チェイン法) ハッシュ関数の値(ハッシュ値)が同じであるレコード同士をリストでつないでおく 下の図のようにハッシュテーブルの各要素には,レコードを直接入れるのではなく,レコードをつないだリストの先頭を指すポインターを入れる 探索の際は,まずハッシュ関数を計算して,ハッシュテーブルから特定のリストを選んで,その後リスト上を探索するという手順になる 1 2 m ・・・・・ Hash Table

開放番地法のデータ挿入手順 Hash Table mark 0 used record 1 free 2 free まず,ハッシュテーブルからハッシュ値が指す要素を調べる. もしそこにデータが入っていなかったら,そこにレコードを入れる.別のレコードがすでにそこに入っていれば,ハッシュテーブルの別の場所を調べ,そこが未使用であればそこへデータを入れ,使用済であればまた別の場所を探すという方法をとる. この方法では,ハッシュ表の各要素が使用中であるか否かを表す印が必要となる 0 used record 1 free 2 free 4 free 3 used record m used record m-1 free mark Hash Table

開放番地法 開放番地法では,要素を調べたときに使用済であった場合に,次にどこの場所を調べるかということを前もって方針を決めておく 線形走査法 使用済であった場合に,次の要素,その次の要素...と添字を1つずつ増やしながら調べていく方法 均一ハッシュ法 違うハッシュ値を持つデータ同士がひとかたまりにならないようにする方法

線形走査法 使用済であった場合に,次の要素,その次の要素...と添字を1つずつ増やしながら調べていく方法 クラスターによる性能低下が起こる 下図では,「1から5」に固まり(クラスター)ができている ハッシュ値が1のレコードを挿入しようとするとき,1から5までは塞がっているので,6の場所に入れる. その付近のハッシュ値を持つデータは次々に固まりに加わっていく. このように.同じ値のハッシュ値だけでなく,違う値のハッシュ値の影響を受けて固まりができていく現象をクラスターという 1 record 2 record 3 record 1 record 4 record 5 record 6 7 m

均一ハッシュ法 関数をm個(関数h1,h2,....hmとし,これらはある同じ値を入力しても全て違う値を返すとする)用意して,最初に関数h1により,ハッシュテーブルを調べ,塞がっていれば次に関数h2を適用して,その場所を調べる.さらに塞がっている場合,h3,h4,...と空いているまで関数によってその場所をみつけていく. これにより,データがバラバラに配置されてクラスターを避ける この方法では,ハッシュ関数の計算の手間が増えて効率が悪くなる

チェイン法と開放番地法の比較 開放番地法 チェイン法 衝突が起ったときに,ハッシュテーブル内の別の場所に格納していく → 扱えるデータの総数はハッシュテーブルの大きさに制限される(欠点) データの削除では,単純にその場所の印を未使用にしてしまうと,探索の時にその場所で止まってしまう. → そこで,新たな印として,削除済ということを表す印を加え,(使用中,未使用,削除済)の3種類の印を用いると,削除済というのは探索に関しては,使用中と同じことになる.削除が多くなると,ハッシュテーブルに無駄な部分が増えて,効率が悪くなる(欠点) チェイン法 大きな欠点は無い 線形リストを使うため若干メモリ使用量が増える

チェイン法のハッシュ関数 ハッシュ関数は,キー値を,一様に分散させるようなものが望ましい ハッシュテーブルの大きさがmである場合: チェイン法の効率をあげるには,データをm本のリストにできるだけ均等に振り分けて,個々のリストをできるだけ短くすることが必要 キーの値に対して,できるだけランダムな値を返すハッシュ関数が望ましい ハッシュ関数の作り方は,キーの種類,とりうる値の範囲に影響される 任意のデータに対して常に一様なばらつきを持ったハッシュ関数を作ることは不可能

チェイン法のハッシュ関数 キー値が正の整数の場合: キーの値をmで割った余りをハッシュ関数とする キー値は0~m-1の範囲の整数に分けられる 同じハッシュ値となるのは,mの倍数だけ離れた値を持つキー ハッシュ関数をできるだけランダムなものにするためには,キーの全てのビットの値が結果に影響することが望ましい mの大きさは,素数をとるのが良いとされる m = 2のK乗とすると,最下位kビットのみでハッシュ値が決まる.データ自体の傾向やハッシュ関数の癖が強調されてばらつきが悪くなってしまうようと言われる キーが文字列の時: 何らかの方法で文字列を整数値に変換して,それをmで割った余りをとるようにすることができる

ハッシュ法の欠点 ハッシュ関数をうまく作って,ハッシュテーブルのサイズmを十分大きくとれば,探索,その他の操作は高速になる 表の中のデータの順序がでたらめになるので,表の中の値を大きさの順に取り出す場合は,新たに整列を行う必要がある. このような場合,整列を必要としない2分探索木などと比べて劣っている

サンプルプログラム #include<stdio.h> #include<stdlib.h> struct RECOAD{ /*レコードを構造体で定義*/ char *value; /*レコードの中身*/ struct RECOAD *next; /*次のレコードを指すポインタ*/ } main(){ struct RECOAD *table[10]; int i; char in[20]; for (i=0;i<10;i++)table[i]=NULL; /*テーブルを初期化*/ for (i=0;i<100;i++){ printf("Input Word (end: %%%%%%) :"); /*語を入力*/ scanf("%s",in);

if (strcmp(in,"%%%")==0)break; else Chain(in,table); /*チェイン法で挿入*/ } while (1){ printf("Search Word (end: %%%%%%) :"); /*探す語を入力*/ scanf("%s",in); else Search(in,table); /*探索*/ Chain(char *in,int *table){ int k,h; char *in2;

struct RECOAD *rec; rec=malloc(sizeof(rec)); /*レコードを作製*/ in2=malloc(20); strcpy(in2,in); /*文字列を格納する領域を作成*/ rec->value=in2; h=0; for (k=0;k<20;k++){ /*ハッシュ値を計算(h=0,1,2,...,9)*/ if (in[k]==NULL)break; h=h+in[k]; } h=h % 10; rec->next=table[h]; /*レコード挿入*/ table[h]=rec;

Search(char *in,int *table){ struct RECOAD *rec; int k,h; h=0; for (k=0;k<20;k++){ /*ハッシュ値を計算(h=0,1,2,...,9)*/ if (in[k]==NULL)break; h=h+in[k]; } h=h % 10; rec=table[h]; while (1){ if (rec==NULL){ printf ("Not Found %s\n",in); break;

if (strcmp(rec->value,in)==0){ printf ("Found %s\n",in); break; } rec=rec->next; /*次のレコード参照*/