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

計算量と実測性能

入力の増加に対する計算量を見積もり、定数倍・キャッシュ・入力分布も含めて実測結果を読み解きます。

学習の目安 約75分 · 更新 2026-10-25

情報の確認基準日:2026-10-26

学習目標

  • O・Ω・Θ記法を用いて時間計算量と空間計算量を導出し、入力サイズに対する増え方を説明できる。
  • 同じ漸近計算量の実装でも、定数倍・メモリアクセス・入力分布・計測方法によって実測が変わる理由を説明できる。

10件で速かった処理が100万件では使えない。反対に、計算量が同じ二つの実装に大きな速度差が出ることもあります。計算量は入力が増えたときの伸び方を考える道具、ベンチマークは特定の条件で実際の時間を確かめる道具です。両方を使って、改善すべき場所を選びます。

まず何をnとするか決める

計算量を述べる前に、入力サイズを定義します。配列の要素数をnとするのか、整数の桁数をnとするのかで意味が変わります。また、数える基本操作にも仮定があります。固定幅整数の加算を一回と数えるモデルと、非常に大きな整数の各桁を処理するモデルは同じではありません。モデルは目的に合わせて明示します。

def total(values):
    result = 0
    for value in values:
        result += value
    return result

def pair_count(values):
    count = 0
    for x in values:
        for y in values:
            if x == y:
                count += 1
    return count

一つ目はn個の要素を一回ずつ見るため、基本操作を定数時間とすれば時間はΘ(n)です。二つ目は各xについてn個のyを見るためn²回の比較となり、Θ(n²)です。nが10倍になると、支配項による仕事量は前者で約10倍、後者で約100倍になります。実時間はほかの要因も受けるため、常に厳密な倍率になるわけではありません。

Oは上界、Θは同じ程度の伸び方

O(g(n))は、十分大きなnで定数倍のg(n)を超えないという漸近的な上界です。Θ(g(n))は上下から定数倍で挟めることを表します。3n+7はΘ(n)ですし、上界としてO(n²)と書くこともできます。普段の会話ではOを代表的な伸び方の意味で使うことがありますが、厳密な説明では上界と一致する評価を区別します。

よく現れる順序は、定数、対数、線形、n log n、二次、指数です。二分探索の比較回数が対数的になるのは、一回ごとに候補をほぼ半分へ減らすからです。100万件でも約20回の比較で絞れます。ここでは整列済みで、途中の要素へ定数時間でアクセスできる、といった前提を忘れないようにします。

最悪・平均・償却は違う問い

最悪計算量は同じサイズの入力の中で最も費用が大きい場合です。平均計算量を語るには、どんな入力がどの確率で来るかを定めます。「普通は速い」だけでは平均の根拠になりません。償却解析は、操作列全体にかかった費用を各操作へならして評価します。入力のランダム性を必ずしも仮定しません。

例えば容量を倍増する動的配列では、拡張時の追加一回に要素コピーが必要でも、n回の追加全体ではコピー数の合計をO(n)へ抑えられます。この場合、追加一回は償却O(1)です。拡張が起きる特定の一回が最悪O(n)であることとは両立します。応答時間の上限が厳しい場面では、この一回の遅延も問題になります。

空間と定数倍も設計に効く

空間計算量は必要なメモリの伸び方です。入力を含む総量と、入力以外に使う補助領域を区別して示します。全要素を複製する処理は補助領域Θ(n)、合計値だけを持つ処理は通常Θ(1)です。メモリを増やして再計算を減らすなど、時間と空間の交換もあります。

同じΘ(n)でも、連続した配列を読む処理と、離れた場所をポインタでたどる処理では、キャッシュの働きが異なります。関数呼出し、文字列の割当て、入出力などの定数倍も効きます。小さな入力では単純な実装が速く、大きな入力では漸近的に有利な実装が逆転することがあります。

測定条件をそろえる

python -m timeit -s "xs = list(range(10000))" "sum(xs)"

測りたい処理と準備を分け、同じ入力、同じ処理系、同じ結果を出す条件で比較します。短い処理は繰り返して測り、複数回の結果のばらつきを見ます。timeitは小さな処理の測定に便利ですが、本番の待ち時間やGC、ネットワーク負荷をそのまま再現するものではありません。実サービスでは分位点や同時実行数も重要です。

理解を確かめる

  • 二重ループは必ずΘ(n²)か。必ずではありません。各ループの範囲や途中終了によって回数が変わります。実行回数の和を数えます。

  • 償却O(1)の追加操作は、どの一回も定数時間か。違います。操作列全体をならした評価であり、特定の一回が高価でもかまいません。

  • O(n)の処理がO(n log n)より常に速いか。有限の入力では定数倍や実装条件で逆転します。入力サイズを変えて測り、伸び方も確かめます。

この単元の概念:時間計算量 償却解析 ベンチマーク 

続けて読む:キャッシュとメモリ階層