実践LESSON 14

この教材で学ぶこと data structure、探索、Big Oを選択理由とともに学びます。

データ構造とアルゴリズム入門

対象読者: 基本文法を学び、処理の速さやデータの持ち方を理解したい人。

この教材でできるようになること

  • データ構造とアルゴリズムを区別できる
  • list、set、mapを用途から選べる
  • 線形探索と二分探索の違いを説明できる
  • Big Oを厳密な時間ではなく増え方として読める

1. 入れ物と手順を分ける

  • データ構造: データをどの形で保持するか
  • アルゴリズム: 目的の結果へ至る手順

同じ検索でも、順不同のlistを先頭から探す場合と、キー付きmapから探す場合では性質が異なります。

2. 基本的なデータ構造

構造 得意なこと 注意点
array/list 順番に並べる、位置で参照 途中挿入や全探索が増えることがある
stack 最後に入れたものから取り出す LIFO
queue 最初に入れたものから取り出す FIFO
set 重複排除、存在確認 順序を目的にしない
map/dict キーから値を探す キー設計が必要

3. 線形探索

def find_index(values: list[int], target: int) -> int | None:
    for index, value in enumerate(values):
        if value == target:
            return index
    return None

最悪の場合、要素をすべて確認します。要素数をnとすると、処理量の増え方はO(n)です。

4. 二分探索

ソート済みのデータなら、中央との比較で探索範囲を半分ずつ減らせます。

def binary_search(values: list[int], target: int) -> int | None:
    low = 0
    high = len(values) - 1

    while low <= high:
        middle = (low + high) // 2
        if values[middle] == target:
            return middle
        if values[middle] < target:
            low = middle + 1
        else:
            high = middle - 1
    return None

探索範囲が半分ずつになるためO(log n)です。ただし、事前にソート済みであるという条件があります。

5. Big Oの読み方

Big Oは特定PCでの秒数ではなく、入力が増えたとき処理量がどう増えるかを見る尺度です。

記法 増え方の例
O(1) mapのキー検索を平均的に見る
O(log n) 二分探索
O(n) 全要素を一度見る
O(n log n) 効率的な比較ソート
O(n²) 全組み合わせを二重loopで比較

小さなデータでは読みやすさを優先できる場合もあります。計測せずに最適化するのではなく、要件、データ量、実測から判断します。

6. 正しさを先に考える

アルゴリズムには少なくとも次を確認します。

  • 空入力
  • 要素が一つ
  • 対象が先頭・中央・末尾
  • 対象がない
  • 重複がある
  • 非常に大きな入力

演習: 重複しない順序付き一覧

入力順を保ちながら、重複した文字列を除外してください。

def unique_in_order(values: list[str]) -> list[str]:
    # 実装する
    ...

解答例

def unique_in_order(values: list[str]) -> list[str]:
    seen: set[str] = set()
    result: list[str] = []
    for value in values:
        if value not in seen:
            seen.add(value)
            result.append(value)
    return result

listだけで存在確認するとデータ増加時に遅くなりやすいため、確認用のsetと順序保持用のlistを組み合わせています。

理解チェック

  • データ構造を用途から選べる
  • O(n)とO(log n)の増え方を説明できる
  • 二分探索にソート済みデータが必要な理由を説明できる
  • 境界値を使ってアルゴリズムを検証できる

次に読む

テストとデバッグで、正しさを継続的に確かめる方法を学びます。