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