アルゴリズムと データ構造 第3回 探索 探索 探索とは データの集合から、目的とする値を持った要素を 探し出すこと 探し出す値の項目:キー データの一部 キーの指定方法はさまざま 一致、範囲指定、近接など 探索失敗する(見つからない)こともあり 探索とコスト 探索アルゴリズム 用途、目的、実行速度、対象のデータ構造などに より使い分け 探索以外にどのような操作を行うかも考慮 単に見つかればOK→計算時間が短ければよい データの追加や削除もあり→追加や削除のコストがあ まり大きくならないように 線形探索 線形探索(逐次探索)とは 目的とするキー値と一致するまでデータを先頭か ら順に探索 探索の終了 探索すべき値と等しい要素があった場合 探索すべき値と等しい要素がなく末端を通り越した場合 探索のコスト n項目あれば平均n/2回 線形探索 7を探索 6 4 3 7 1 9 8 1 9 8 探索成功 5を探索 6 4 3 7 探索失敗 線形探索 線形探索プログラム(無限ループ版) int search(const int a[], int n, int key) { int i = 0; while (1) { if (i == n) return (-1); if (a[i] == key) return (i); i++; } } /* 無限ループ */ /* 探索失敗 */ /* 探索成功 */ /* 次の要素 */ 線形探索 線形探索プログラム(for版) int search(const int a[], int n, int key) { int i; for (i = 0; i < n; i++) if (a[i] == key) return (i); return (-1); } /* 探索成功 */ /* 探索失敗 */ 線形探索 番兵法 データの末尾まで探索したかのチェックを省略 末尾にキー値を格納:番兵 データ内に一致する値がなくても必ず番兵と一致 一致位置が末尾なら探索失敗と判断 線形探索 番兵法による線形探索(無限ループ版) int search(const int a[], int n, int key) { int i = 0; a[n] = key; /* 末尾に番兵を配置 */ while (1) { /* 無限ループ */ if (a[i] == key) break; /* 探索成功 */ i++; /* 次の要素 */ } return (i == n ? -1 : i); /* 末尾なら探索失敗 */ } 線形探索 番兵法による線形探索(for版) int search(const int a[], int n, int key) { int i; a[n] = key; /* 末尾に番兵を配置 */ for (i = 0; ; i++) /* ループ終了条件不要 */ if (a[i] == key) break; /* 探索成功 */ return (i == n ? -1 : i); /* 末尾なら探索失敗 */ } 2分探索 2分探索とは 要素があらかじめソート(整列)されているデータ から効率よく探索を行うアルゴリズム 中央の値に着目し、その値より大きいか小さいか で探索範囲を半分に絞り込み 探索のコスト n項目あれば平均log(2)n回 2分探索 39を探索 5 7 15 28 29 31 39 58 < 39探索成功 6を探索 5 7 15 < 6 探索失敗 >6 >6 28 29 31 >6 39 58 68 70 95 > 39 68 70 95 2分探索 pl 39を探索 5 7 15 28 29 pc plplpc pr pc 31 68 39 58 < 39探索成功 pl pc plpr pl pc plpc pr 6を探索 5 7 15 < 6 探索失敗 >6 >6 28 pr pc 29 31 >6 pr 70 95 > 39 pr 39 58 68 70 95 計算量 アルゴリズムの性能を客観的に評価する尺度 時間計算量:実行に要する時間を評価 領域計算量:実行に要するメモリ領域を評価 オーダー 時間計算量を表現する方法 各部の計算量のうち、より大きい計算量が支配 線形探索:O(n) 2分探索:O(log(2)n) ハッシュ法 ソート済み配列の操作 データの追加:格納位置からあとの配列をすべて 1つずつ移動し、格納位置をあける必要あり データの削除:削除位置からあとの配列をすべて 1つずつ移動し、削除位置を埋める必要あり ハッシュ法とは 格納する値を元に、簡単な計算で格納位置を求 め、効率よく格納、探索を行う方法 ハッシュ法 ハッシュ法の原理 キー値からハッシュ値(配列の場合は添え字)を 求める:ハッシュ関数 キー値 5 6 14 20 29 34 37 51 69 75 13で割った剰余 5 6 1 7 3 8 11 12 4 10 5 6 7 8 9 10 11 12 5 6 20 34 - 75 37 51 0 1 2 3 4 - 14 - 29 69 ハッシュ法 ハッシュ法による要素の挿入 0 1 2 3 4 - 14 - 29 69 5 6 7 8 9 10 11 12 5 6 20 34 - 75 37 51 5 6 7 8 9 10 11 12 5 6 20 34 35 75 37 51 35を挿入:35=13x2+9 ハッシュ値9 添え字9の位置に挿入 0 1 2 3 4 - 14 - 29 69 ハッシュ法 衝突 格納すべきバケットが重複 対処法 チェイン法:同一ハッシュ値を持つ要素を線形リストで 管理 オープンアドレス法:空きバケットが見つかるまでハッ シュの繰り返し ハッシュ法 チェイン法(オープンハッシュ法) 0 1 13 14 2 3 4 5 6 7 8 29 69 17 5 6 33 20 46 34 69 17を挿入 33を挿入 46を挿入 33を削除 ハッシュ値7 ハッシュ値4 20 9 10 11 12 75 37 51 ハッシュ法 オープンアドレス法(クローズドハッシュ法) 衝突が起きたら再ハッシュ ハッシュ関数のほかに再ハッシュ関数 空きバケットを求め順にたぐる→線形探査法 要素削除のときの問題 すでに削除されたのと同じ要素が再ハッシュで配置さ れていた場合、たどり着けない→削除済みフラグ ハッシュ法 オープンアドレス法(クローズドハッシュ法) 0 1 2 3 4 - 14 - 29 69 18を挿入 5 6 7 8 9 10 11 12 5 6 18 - 34 - 75 37 51 18 18 18 衝突 衝突 再ハッシュ値7:添え字7の位置に挿入 ハッシュ値5:添え字5の位置に挿入 再ハッシュ値6:添え字6の位置に挿入
© Copyright 2024 ExpyDoc