探索アルゴリズム
データの中から特定の要素を見つけるアルゴリズム。
線形探索
配列の先頭から順番に要素を検索する手法。
二分探索
ソート済みの配列で中央値と比較しながら検索範囲を半分にする手法。
ターゲット
検索する値。
ソート済み
要素が昇順または降順に並んでいる状態。
時間計算量
アルゴリズムの実行時間を表す指標。
空間計算量
アルゴリズムが使用するメモリ量を表す指標。
線形探索
なぜ線形探索が必要か?
線形探索は、最もシンプルな探索アルゴリズムの1つです。理解しやすく、実装も簡単です。特に、データがソートされていない場合や、データサイズが小さい場合に適しています。
いつ使うか?
- データがソートされていない場合
- データサイズが小さい場合
- 最初の要素を見つけるだけでよい場合
- メモリ使用量が重要でない場合
実践テクニック
早期終了を活用する
線形探索では、ターゲットが見つかった時点で探索を終了できます。これにより、最悪ケースでもO(n)になります。
計算量を理解する
線形探索の時間計算量はO(n)です。これは、データサイズが大きくなるにつれて、探索時間が線形的に増加することを意味します。
# 線形探索の実装def linear_search(arr, target): for i in range(len(arr)): if arr[i] == target: return i return -1
# 使用例arr = [11, 23, 35, 47, 59, 71]target = 47result = linear_search(arr, target)print(f"見つかった位置: {result}") # 見つかった位置: 2二分探索
なぜ二分探索が必要か?
二分探索は、ソート済みの配列で高速に要素を検索できるアルゴリズムです。時間計算量はO(log n)で、線形探索のO(n)よりも効率的です。特に、データサイズが大きい場合に適しています。
いつ使うか?
- データがソート済みの場合
- データサイズが大きい場合
- 頻繁な検索が必要な場合
- ランダムアクセスが不要な場合
実践テクニック
中央値の計算
中央値の計算は、二分探索の重要な部分です。`(left + right) // 2` で計算しますが、整数除算の切り捨てに注意が必要です。
境界条件を正しく設定する
境界条件を`left <= right`とすることで、無限ループを回避します。また、初期値を`left = 0, right = len(arr) - 1`とすることで、最初の要素から検索を開始します。
再帰と反復の使い分け
二分探索は、再帰と反復の両方で実装できます。再帰は簡潔ですが、スタックオーバーフローのリスクがあります。反復は少し複雑ですが、メモリ効率が良いです。
# 二分探索の実装def binary_search(arr, target): left = 0 right = len(arr) - 1 while left <= right: mid = (left + right) // 2 if arr[mid] == target: return mid elif arr[mid] < target: left = mid + 1 else: right = mid - 1 return -1
# 使用例arr = [11, 23, 35, 47, 59, 71]target = 47result = binary_search(arr, target)print(f"見つかった位置: {result}") # 見つかった位置: 2比較
線形探索と二分探索の特徴を比較する。
| 特徴 | 線形探索 | 二分探索 |
|---|---|---|
| 時間計算量 | O(n) | O(log n) |
| 空間計算量 | O(1) | O(1) |
| 前提条件 | なし | ソート済み |
| ランダムアクセス | はい | はい |
計算量
探索アルゴリズムの計算量を理解する。
# 探索アルゴリズムの比較import time
arr = list(range(10000))target = 9999
# 線形探索start = time.time()linear_search(arr, target)end = time.time()print(f"線形探索: {end - start:.6f}秒")
# 二分探索arr.sort() # ソート済みの配列start = time.time()binary_search(arr, target)end = time.time()print(f"二分探索: {end - start:.6f}秒")使用例
探索アルゴリズムの実際の使用例を確認する。
# 探索アルゴリズムの使用例# データベースの検索users = [ {"id": 1, "name": "Alice", "email": "alice@example.com"}, {"id": 2, "name": "Bob", "email": "bob@example.com"}, {"id": 3, "name": "Charlie", "email": "charlie@example.com"},]
# 線形探索でユーザーを検索target_id = 2found_user = Nonefor user in users: if user["id"] == target_id: found_user = user break
if found_user: print(f"ユーザーが見つかりました: {found_user['name']}")else: print("ユーザーが見つかりませんでした")
# 二分探索でユーザーを検索(IDでソート済みと仮定)sorted_users = sorted(users, key=lambda x: x["id"])target_id = 2found_user = binary_search(sorted_users, target_id)
if found_user != -1: print(f"ユーザーが見つかりました: {sorted_users[found_user]['name']}")else: print("ユーザーが見つかりませんでした")合格ライン
線形探索を実装できる
二分探索を実装できる
線形探索と二分探索の違いを理解している
探索アルゴリズムの計算量を理解している
探索アルゴリズムの使い分けができる
演習課題
課題1: 線形探索の実装
線形探索を実装し、配列から要素を検索してください。
課題2: 二分探索の実装
二分探索を実装し、ソート済みの配列から要素を検索してください。
課題3: 探索アルゴリズムの比較
線形探索と二分探索の計算量を比較し、それぞれの特徴を説明してください。
参考文献
この記事は以下の公的ガイドライン/標準に基づいています。
- Python Lists - 公式ドキュメント
- Binary Search in Python - Real Python チュートリアル
- Search Algorithm - Wikipedia