edubun
日本語

どれくらい速い?ビッグO記法

1秒に10億ステップなら、100万個の値に対して n² の方法は約17分かかりますが、n log n の方法は0.02秒です。

正確な回数より増え方が大切

ここまでは、比較45回、交換4回、調べる回数20回のように、ステップを正確に数えてきました。正確な回数は小さな例では役に立ちますが、バブルソートが途中で止まるかどうか、ピボットをどう選ぶかといった細かい点に左右されます。入力が大きくなると、ほかのすべてを圧倒するものが1つあります。nが大きくなるにつれて回数がどう増えるかです。ステップ数が n² のように増えるアルゴリズムは、どんなに念入りに調整しても、いずれは n log n のように増えるアルゴリズムに負けます。

ビッグO記法は、その増え方を短く書く方法です。アルゴリズムが O(n²)(「オーダー n の2乗」と読みます)であると書くのは、nが大きいとき、ステップ数がある定数かける n² 以下になるという意味です。2つのルールを使えば簡単に扱えます。定数倍は捨てます。3n も n/2 もどちらも O(n) です。いちばん速く増える項だけを残します。選択ソートの比較回数 n²/2 − n/2 は O(n²) です。nが大きいと、ほとんどが n² の部分になるからです。MITの6.006の講義でも、データ構造やソートを漸近的な実行時間で比べるときに、同じ考え方を使っています。

よく出てくる増え方

  • O(1)、定数時間。仕事量がnによらない。リストの最初の値や、位置がわかっている値を読むことなど。
  • O(log n)、対数時間。1ステップごとに問題が半分になる。二分探索。100万個の値で約20ステップ。
  • O(n)、線形時間。各値を1回ずつ扱う。線形探索、最大の値を見つけること、リストの合計を求めることなど。
  • O(n log n)。マージソートと、平均の場合のクイックソート。比較によるソートで達成できる最善。
  • O(n²)、2乗時間。すべての組を調べる。最悪の場合のバブルソート、選択ソート、挿入ソート、または入れ子になった2つのループ。
  • O(2ⁿ)、指数時間。値が1つ増えるごとに仕事量が2倍になる。n個のものの部分集合をすべて試すことや、ハノイの塔でn枚の円盤を動かすことなど。
読み込み中

ドラッグで回転、スクロールまたはピンチで拡大・縮小。

同じ軸にかいた6つの増え方。nを動かし、対数目盛りを切りかえてみましょう。表には、そのnでのステップ数と、1秒に10億ステップで100万個の値を処理するときの時間が出ます。

数を秒になおすと

コンピューターが1秒に10億(10⁹)回の基本ステップを行うとしましょう。プロセッサのコア1つとして手ごろな概数です。100万個の値に対して、それぞれの増え方が何を意味するかを見てみます。O(log n) は約20ステップで、1マイクロ秒よりずっと短い時間です。O(n) は100万ステップで、1ミリ秒です。O(n log n) は約2,000万(20 million)ステップで、0.02秒です。O(n²) は 10¹² ステップで、1,000秒、約17分です。O(2ⁿ) は終わりません。2の100万乗は300,000桁を超える数です。アルゴリズムを正しく選ぶことが、たいてい速いコンピューターを買うよりずっと大切なのはこのためです。10倍速い機械なら17分は1.7分になりますが、O(n²) から O(n log n) に切りかえれば50分の1秒になります。

増え方n = 1,000,000 のときのステップ数1秒に 10⁹ ステップのときの時間
O(1)1約1ナノ秒
O(log n)約20回約20ナノ秒
O(n)1,000,0001ミリ秒
O(n log n)約20,000,000約0.02秒
O(n²)1,000,000,000,000約17分
O(2ⁿ)300,000桁を超える終わらない

コードからビッグOを読み取る

増え方は、コードの形から直接読み取れることがよくあります。リストを1回たどるループは O(n) です。どちらもリスト全体をたどる2つのループが入れ子になっていれば O(n²) です。外側のn回それぞれで、内側のループが最大n回まわるからです。while (n > 1) n = Math.floor(n / 2) のように毎回数を半分にするループは O(log n) で、1,000から始めると9回、100万からなら19回まわります。順に続く手順は足し合わされ、大きいほうの項が勝ちます。O(n) のループの後に O(n²) のループが続けば、全体は O(n²) です。

// O(n): 1回たどる
let total = 0;
for (const x of list) total += x;

// O(n²): すべての組
for (let i = 0; i < list.length; i++)
  for (let j = i + 1; j < list.length; j++)
    if (list[i] === list[j]) console.log("duplicate", list[i]);

// O(log n): 半分にする
let k = list.length, rounds = 0;
while (k > 1) { k = Math.floor(k / 2); rounds++; }

最善、平均、最悪の場合

1つのアルゴリズムでも、入力によってふるまいが大きく違うことがあります。挿入ソートは、すでに整列したリストでは O(n)、逆順のリストでは O(n²) です。クイックソートは平均で O(n log n)、いつも悪いピボットを選ぶと O(n²) です。どの場合かを言わずにビッグOを1つだけ挙げるときは、ふつう最悪の場合を指します。それが保証になるからです。アルゴリズムはそれより悪くなることはありません。ビッグOには省かれていることもあります。定数倍を無視するので、小さな入力では、手順がとても簡単な O(n²) の方法が O(n log n) の方法に勝つことがあります。実際の多くのソート処理が、リストの短い部分では挿入ソートに切りかえるのはそのためです。

ビッグOは時間だけでなくメモリも表せます。マージソートは2つ目のリストのために O(n) の追加メモリを使い、挿入ソートはいくつかの変数だけの O(1) の追加メモリを使います。
ビッグO定数倍を無視した、nに対するステップ数の増え方
O(1)定数時間:どんなnでも同じ仕事量
O(log n)対数時間:二分探索のように、1ステップごとに半分にする
O(n)線形時間:入力を1回たどる
O(n log n)マージソート。比較によるソートの最善
O(n²)2乗時間:すべての組、入れ子の2つのループ
O(2ⁿ)指数時間:1つ増えるごとに2倍になる
最悪の場合保証:アルゴリズムがこれより多くの仕事をすることはない
  1. 3n² + 5n + 2 をビッグO記法で表すとどうなりますか?
    • O(n)
    • O(n²)
    • O(3n²)
    • O(n² + n)
  2. それぞれn個の値をたどる2つのループが入れ子になっています。ビッグOは?
    • O(n)
    • O(2n)
    • O(n²)
    • O(log n)
  3. 二分探索は
    • O(1)
    • O(log n)
    • O(n)
    • O(n log n)
  4. O(n²) の方法で1,000個の値に2秒かかります。10,000個の値ではおよそ何秒かかりますか?
  5. O(n) の方法で1,000個の値に2秒かかります。10,000個の値ではおよそ何秒かかりますか?
  6. 1秒に 10⁹ ステップのとき、10¹² ステップ(100万個の値に対する n² の方法)には何秒かかりますか?
  7. nが64から始まるとき、while (n > 1) n = Math.floor(n / 2) は何回まわりますか?
  8. あるプログラムは O(n) のループを実行し、次に O(n²) のループを実行します。全体では
    • O(n)
    • O(n²)
    • O(n³)
    • O(n + 2)
  9. すでに整列したリストに対する挿入ソートは
    • O(1)
    • O(n)
    • O(n log n)
    • O(n²)
  10. 小さな入力では、O(n²) の方法が O(n log n) の方法に勝つことがあるのはなぜですか?
    • ビッグOは定数倍を無視し、簡単な方法のほうが1ステップあたりの仕事が少ないことがあるから
    • nが小さいとビッグOはまちがっているから
    • どんなnでも n² は n log n より小さいから
    • 小さな入力はいつも整列しているから
  11. マージソートの追加メモリは
    • O(1)
    • O(log n)
    • O(n)
    • O(n²)
  12. これらの増え方を、増え方のおそいものから速いものへ順に並べましょう。
ポイント
  • ビッグOは、定数倍や小さな項を無視して、nに対してステップ数がどう増えるかを表します。
  • よく出てくる増え方:1、log n、n、n log n、n²、2ⁿ。
  • 1秒に 10⁹ ステップで100万個の値なら、n log n は約0.02秒、n² は約17分。
  • ループ1つは O(n)、入れ子の2つのループは O(n²)、半分にしていくのは O(log n)。
  • ビッグOを1つだけ挙げるときは、ふつう最悪の場合を指す。
このコースの出典 (11)
  • MIT OpenCourseWare 6.006 Introduction to Algorithms, Spring 2020 (Demaine, Ku, Solomon)
  • lecture notes 1 Introduction, 3 Sorting, 9 Breadth-First Search, 10 Depth-First Search (ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/pages/lecture-notes) and Fall 2011 lecture 13 BFS notes (ocw.mit.edu/courses/6-006-introduction-to-algorithms-fall-2011)
  • Cormen, Leiserson, Rivest, Stein, Introduction to Algorithms (MIT Press)
  • with the CLRS-based Khan Academy algorithms unit by Thomas Cormen and Devin Balkcom of Dartmouth (khanacademy.org/computing/computer-science/algorithms: binary search, selection sort analysis, merge sort, quicksort overview and analysis)
  • MacTutor History of Mathematics, Al-Khwarizmi (mathshistory.st-andrews.ac.uk/Biographies/Al-Khwarizmi: word algorithm from the Latin title Algoritmi de numero Indorum)
  • D. E. Joyce, Euclid's Elements Book VII Propositions 1 and 2 (mathcs.clarku.edu/~djoyce/elements/bookVII)
  • Wolfram MathWorld, Merge Sort (mathworld.wolfram.com/MergeSort.html: proposed by John von Neumann in 1945, after Knuth 1998 p. 159)
  • Stanford CS "Tony Hoare: Quicksort" (cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/tony-hoare/quicksort.html: devised while a student at Moscow State University for Russian-English machine translation with a tape dictionary, programmed in Algol 60 and published 1961; the year 1959 from the Wikipedia Quicksort article and its cited sources)
  • Bodleian Libraries, Ada Lovelace (blogs.bodleian.ox.ac.uk/adalovelace: 1843 paper, Note G Bernoulli numbers)
  • Fourmilab text of Menabrea's Sketch with Lovelace's notes (fourmilab.ch/babbage/sketch.html)
  • Seven Bridges of Konigsberg (Euler 1736) and Tower of Hanoi (Edouard Lucas, 1883) checked against the Wikipedia articles and their cited sources.

確認日: 2026-10-17