edubun
Русский

Насколько быстро? Нотация «O большое»

При миллиарде шагов в секунду метод n² на миллионе значений работает около 17 минут; метод n log n работает 0.02 секунды.

Рост важнее точного счёта

До сих пор мы считали шаги точно: 45 сравнений, 4 обмена, 20 проверок. Точный счёт полезен для маленьких примеров, но зависит от деталей, например останавливается ли сортировка пузырьком раньше или как выбирается опорный элемент. Когда входные данные становятся большими, одно перевешивает всё остальное: как растёт счёт с ростом n. Алгоритм, число шагов которого растёт как n², рано или поздно проиграет алгоритму с ростом n log n, как бы тщательно ни настроили первый.

Нотация «O большое» является краткой записью этого роста. Запись O(n²), читается «O большое от n в квадрате», означает, что при больших n число шагов не больше некоторой константы, умноженной на n². Два правила упрощают работу с ней. Отбрасывай постоянные множители: 3n и n/2 оба O(n). Оставляй только самое быстро растущее слагаемое: n²/2 − n/2, число сравнений сортировки выбором, является O(n²), потому что при больших n почти всё приходится на часть n². Курс MIT 6.006 использует ту же идею, когда сравнивает структуры данных и сортировки по асимптотическому времени работы.

Распространённые скорости роста

  • O(1), константа. Работа не зависит от n: прочитать первое значение списка или значение на известной позиции.
  • O(log n), логарифм. Каждый шаг делит задачу пополам: двоичный поиск. Миллион значений, около 20 шагов.
  • O(n), линейный рост. Каждое значение обрабатывается один раз: линейный поиск, поиск наибольшего значения, сумма списка.
  • O(n log n). Сортировка слиянием и быстрая сортировка в среднем. Лучшее, на что способна сортировка сравнениями.
  • O(n²), квадратичный рост. Просматривается каждая пара: сортировки пузырьком, выбором и вставками в худшем случае или два цикла, вложенные один в другой.
  • O(2ⁿ), экспонента. Работа удваивается с каждым лишним значением: перебор всех подмножеств из n предметов или перекладывание n дисков в Ханойской башне.
Загрузка

Перетащи, чтобы повернуть. Колёсико или щипок для масштаба.

Шесть скоростей роста на одних осях. Двигай n и включи логарифмическую шкалу; в таблице число шагов при твоём n и время для миллиона значений при миллиарде шагов в секунду.

Что числа значат в секундах

Пусть компьютер делает миллиард (10⁹) базовых шагов в секунду, это честное круглое число для одного ядра процессора. Вот что каждая скорость роста значит для миллиона значений. O(log n) около 20 шагов, гораздо меньше микросекунды. O(n) миллион шагов, одна миллисекунда. O(n log n) около 20 миллионов шагов, 0.02 секунды. O(n²) 10¹² шагов, тысяча секунд, около 17 минут. O(2ⁿ) не закончить никогда: 2 в степени миллион является числом, в котором больше 300 000 цифр. Поэтому выбор правильного алгоритма обычно важнее покупки более быстрого компьютера. Машина в десять раз быстрее превращает 17 минут в 1.7 минуты; переход от O(n²) к O(n log n) превращает их в пятидесятую долю секунды.

РостШагов при n = 1 000 000Время при 10⁹ шагов в секунду
O(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 большое» по коду

Скорость роста часто видна прямо по форме кода. Один цикл по списку даёт O(n). Два цикла, один внутри другого, оба по списку, дают O(n²): на каждый из n кругов внешнего цикла внутренний делает до n кругов. Цикл, который каждый раз делит число пополам, например while (n > 1) n = Math.floor(n / 2), даёт O(log n): от 1000 он выполняется 9 раз, от миллиона 19 раз. Шаги, идущие один за другим, складываются, и побеждает большее слагаемое: цикл O(n), за которым идёт цикл O(n²), в целом даёт O(n²).

// O(n): один проход
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++; }

Лучший, средний и худший случай

Один алгоритм может вести себя совсем по-разному на разных входных данных. Сортировка вставками работает за O(n) на уже отсортированном списке и за O(n²) на обратном. Быстрая сортировка в среднем O(n log n), а при постоянно плохих опорных элементах O(n²). Когда называют одну оценку «O большое», не уточняя случай, обычно имеют в виду худший, потому что это гарантия: хуже алгоритм не сработает никогда. «O большое» кое-что и упускает. Оно не учитывает постоянные множители, поэтому на маленьких входных данных метод O(n²) с очень простыми шагами может обогнать метод O(n log n). Поэтому многие настоящие процедуры сортировки переходят на сортировку вставками для коротких кусков списка.

«O большое» может описывать не только время, но и память. Сортировка слиянием использует O(n) дополнительной памяти на второй список; сортировка вставками использует O(1) дополнительной памяти, всего несколько переменных.
«O большое»Как растёт число шагов с ростом n без учёта постоянных множителей
O(1)Константа: одинаковая работа при любом n
O(log n)Логарифм: деление пополам на каждом шаге, как в двоичном поиске
O(n)Линейный рост: один проход по входным данным
O(n log n)Сортировка слиянием; лучшее для сортировки сравнениями
O(n²)Квадратичный рост: каждая пара, два вложенных цикла
O(2ⁿ)Экспонента: удваивается с каждым лишним предметом
худший случайГарантия: алгоритм никогда не делает больше этого
  1. Как записать 3n² + 5n + 2 в нотации «O большое»?
    • O(n)
    • O(n²)
    • O(3n²)
    • O(n² + n)
  2. Два цикла, вложенные один в другой, каждый по n значениям. Какое «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²) работает 2 секунды на 1000 значений. Сколько примерно секунд на 10 000 значений?
  5. Метод O(n) работает 2 секунды на 1000 значений. Сколько примерно секунд на 10 000 значений?
  6. Сколько секунд занимают 10¹² шагов (метод n² на миллионе значений) при 10⁹ шагов в секунду?
  7. Сколько раз выполнится while (n > 1) n = Math.floor(n / 2), если n вначале равно 64?
  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 большое» не учитывает постоянные множители, а более простой метод может делать меньше на каждом шаге
    • «O большое» неверно при малых n
    • n² меньше n log n при любом n
    • Маленькие входные данные всегда отсортированы
  11. Дополнительная память сортировки слиянием составляет
    • O(1)
    • O(log n)
    • O(n)
    • O(n²)
  12. Расставь скорости роста от самой медленной к самой быстрой.
Главное
  • «O большое» описывает, как растёт число шагов с ростом n, без постоянных множителей и меньших слагаемых.
  • Частые скорости: 1, log n, n, n log n, n², 2ⁿ.
  • Миллион значений при 10⁹ шагов/с: n log n около 0.02 с, n² около 17 минут.
  • Один цикл даёт O(n); два вложенных цикла O(n²); деление пополам O(log n).
  • Если названа одна оценка «O большое», обычно имеется в виду худший случай.
Источники курса (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