2026年1月23日金曜日

【Java】アルゴリズムの通信簿?計算量「O(オーダー)記法」をわかりやすく解説!

 前回、単純選択法(O(n^2))と Arrays.sort()O(n \log n))の圧倒的な速さの違いに触れました。

今回は、その「O」という記号が一体何を表しているのか、そして自分の書いたコードをどう評価すればいいのかを徹底解説します。




1. O(オーダー)記法とは何か?


O記法とは、**「データの量 (n) が増えたときに、処理時間がどれくらいの勢いで増えるか」**をざっくりと表した指標です。

プログラムの実行時間は、パソコンの性能によって変わります。しかし、「データが2倍になったら手間が4倍になる」という増え方の法則は、どんなマシンでも変わりません。この不変の法則を評価するのがO記法です。




2. よく見る「オーダー」と代表的アルゴリズム


効率が良い順に、代表的な処理を並べました。

オーダー名前イメージ代表的なアルゴリズム
O(1)定数時間1億件でも一瞬配列の指定要素へのアクセス
O(\log n)対数時間増えてもほぼ遅くならない二分探索(Binary Search)
O(n)線形時間データ量に比例して増える線形探索、1重ループの全件チェック
O(n \log n)線形対数時間非常に効率が良いArrays.sort()(クイックソート等)
O(n^2)二乗時間増えると急激に重くなる単純選択法、バブルソート
O(2^n)指数時間爆発的に増える愚直なフィボナッチ数列の再帰


3. 探索とソートの「実力差」


データが 100万件 になった時の計算回数で比較してみましょう。


探索(データを探す)


  • 線形探索 (O(n)):1,000,000回(全部見る必要がある)

  • 二分探索 (O(\log n)):わずか 20回 程度


ソート(並べ替える)


  • 単純選択法 (O(n^2)):1,000,000,000,000回(1兆回・数日かかる)

  • クイックソート等 (O(n \log n)):約 20,000,000回(一瞬で終わる)




4. 「最悪」「平均」…どの指標を見るべき?


アルゴリズムは、データの並び順(運)によって速さが変わります。

  1. 最悪実行時間 (Worst case)

    • 「どれだけ運が悪くてもこれ以上はかからない」という保証。エンジニアが最も重視する指標です。ここを見積もらないと、特定のデータでシステムが止まるリスクがあります。

  2. 平均実行時間 (Average case)

    • 何度も実行した時の平均。実務上の体感速度に近い指標です。




5. 自分のコードの計算量を判定する「3つの基本ルール」


自分の書いたメソッドをどう評価すればいいのか、簡単なルールがあります。

① ループ(for文)の入れ子を数える


  • 1重ループO(n)

  • 2重ループO(n^2)

    処理の「深さ」がそのままオーダーに直結します。

② 「半分にする」処理を探す


範囲を毎回半分に絞り込むロジックがあれば、それは O(\log n) です。これは「非常に効率が良いコード」の証です。

③ 定数(回数が決まっている処理)は無視する


「10回だけ回るループ」などは、データ量 n がいくら増えても手間が変わらないため O(1) 扱い。計算量の計算からは除外してOKです。




6. ツールで計測する:JMH


「理論上の計算量」ではなく「実際の速度」を精密に測りたい場合は、Java標準のベンチマークツール JMH (Java Microbenchmark Harness) を使います。

Javaは実行中にコードを最適化するため、単純なストップウォッチ(currentTimeMillis)では正確に測れません。JMHを使えば、ナノ秒単位で統計的なパフォーマンスを測定できます。




7. まとめ


  • O記法は「データ増に対する耐性」を表すもの。

  • ループの入れ子を意識するだけで、自分のコードの限界が見えてくる。

  • 実務では最悪実行時間を意識して、破綻しないコードを選ぶ。




0 件のコメント:

コメントを投稿

【Java】数学の「ラムダ表現」から学ぶJavaラムダ式の実装と制限

Java 8で導入された「ラムダ式」。そのルーツは数学の「ラムダ計算」にあります。数学的な美しさと、Javaの実装における具体的なメリット・制限を整理して解説します。 1. 数学におけるラムダ表現 通常、関数は $f(x) = x + 1$ のように名前を付けて定義しますが、ラ...