mirror of
https://github.com/krahets/hello-algo.git
synced 2026-11-13 01:08:11 +08:00
* Retranslate the complete Japanese online edition from Chinese * Fit Japanese homepage labels and localize heading permalinks * Point Japanese contribution instructions to the Japanese preview * Replace locale conditionals with multilingual UI tables
6.8 KiB
6.8 KiB
探索アルゴリズムを改めて考える
探索アルゴリズム(searching algorithm)は、配列、連結リスト、木、グラフなどのデータ構造から、特定の条件を満たす一つまたは複数の要素を探すために使います。
探索アルゴリズムは、実装の考え方によって次の二種類に分けられます。
- データ構造を走査して目的の要素を見つける方法です。配列、連結リスト、木、グラフの走査などが該当します。
- データの構造や既知の情報を利用して、効率よく要素を探す方法です。二分探索、ハッシュ探索、二分探索木による探索などが該当します。
これらはすでに前の章で紹介した内容なので、探索アルゴリズムは私たちにとってなじみのないものではありません。この節では、より体系的な視点から探索アルゴリズムを改めて考えます。
全探索
全探索は、データ構造の各要素を走査して目的の要素を見つけます。
- 「線形探索」は、配列や連結リストなどの線形データ構造に適しています。一方の端から要素を順に訪問し、目的の要素を見つけるか、見つからないままもう一方の端に達するまで続けます。
- 「幅優先探索」と「深さ優先探索」は、グラフや木を走査する二つの戦略です。幅優先探索は開始ノードから層ごとに探索し、近いノードから遠いノードへと訪問します。深さ優先探索は開始ノードから一本の経路を行き止まりまで進み、戻って別の経路を試し、データ構造全体を走査するまで続けます。
全探索の長所は単純で汎用性が高く、データの前処理や追加のデータ構造が不要なことです。
一方、時間計算量は $O(n)$ です。n は要素数なので、データが多い場合は性能が低くなります。
データの特性に応じた探索
データ固有の性質(整列済みであることなど)を利用して探索過程を最適化し、目的の要素をより効率よく見つける方法です。
- 「二分探索」は、データが整列済みであることを利用して効率よく探索します。配列にのみ適用できます。
- 「ハッシュ探索」は、ハッシュテーブルを利用し、検索するデータと目的のデータをキーと値のペアとして対応付けて照会します。
- 「木探索」は、二分探索木などの特定の木構造でノードの値を比較し、候補となるノードを素早く除外して目的の要素を見つけます。
これらのアルゴリズムの長所は効率が高く、時間計算量が $O(\log n)$、さらには O(1) にもなることです。
ただし、利用にはデータの前処理が必要となることが多いです。例えば、二分探索では配列をあらかじめソートする必要があり、ハッシュ探索と木探索では追加のデータ構造が必要です。それらの維持にも時間と領域が余分にかかります。
!!! tip
データの特性に応じた探索アルゴリズムは、検索アルゴリズムとも呼ばれ、**主に特定のデータ構造から目的の要素を素早く取得するために使います**。
探索方法の選択
大きさ n のデータ集合から目的の要素を探すには、線形探索、二分探索、木探索、ハッシュ探索などの方法が使えます。それぞれの仕組みを下図に示します。
これらの方法の操作効率と特徴を下表に示します。
表 探索アルゴリズムの効率の比較
| 線形探索 | 二分探索 | 木探索 | ハッシュ探索 | |
|---|---|---|---|---|
| 要素の探索 | O(n) |
O(\log n) |
O(\log n) |
O(1) |
| 要素の挿入 | O(1) |
O(n) |
O(\log n) |
O(1) |
| 要素の削除 | O(n) |
O(n) |
O(\log n) |
O(1) |
| 追加領域 | O(1) |
O(1) |
O(n) |
O(n) |
| データの前処理 | / | ソート O(n \log n) |
木の構築 O(n \log n) |
ハッシュテーブルの構築 O(n) |
| データの整列状態 | 未整列 | 整列済み | 整列済み | 未整列 |
探索アルゴリズムの選択は、規模、必要な探索性能、データの照会と更新の頻度などにも左右されます。
線形探索
- 汎用性が高く、データの前処理が不要です。照会が一回だけなら、ほかの三つの方法では前処理の時間が線形探索の時間より長くなります。
- データが少ない場合に適しています。この場合、時間計算量が効率に与える影響は小さくなります。
- データを追加で管理する必要がないため、更新頻度が高い場合に適しています。
二分探索
- データが多い場合に適しており、効率が安定しています。最悪時間計算量は
O(\log n)です。 - 配列の格納には連続したメモリ領域が必要なので、データが多すぎる場合には適しません。
- 整列済み配列の維持にかかる負担が大きいため、データを頻繁に追加・削除する場合には適しません。
ハッシュ探索
- 平均時間計算量が
O(1)なので、高い照会性能が求められる場合に適しています。 - ハッシュテーブルはデータの順序を維持できないため、整列済みデータや範囲検索が必要な場合には適しません。
- ハッシュ関数とハッシュ衝突への対処方法に大きく依存し、性能が悪化するリスクが比較的高くなります。
- 衝突をできるだけ減らして照会性能を高く保つために追加領域が必要なので、データが多すぎる場合には適しません。
木探索
- 木のノードはメモリ内に分散して格納されるため、膨大な量のデータにも適しています。
- データの順序の維持や範囲検索が必要な場合に適しています。
- ノードの追加・削除を続けるうちに二分探索木が偏り、時間計算量が
O(n)に悪化する可能性があります。 - AVL 木や赤黒木を使えば、各操作を安定して
O(\log n)で実行できますが、平衡を維持するための追加の処理が必要になります。
