Перейти к основному содержимому

Цикл внутри цикла

O(n²) означает квадратичное время: объём работы растёт как квадрат размера входных данных. В два раза больше элементов — в четыре раза больше шагов. В десять раз больше элементов — в сто раз больше шагов.

Характерная форма в коде — цикл внутри цикла, причём оба проходят по одним и тем же данным. Внешний цикл выполняется n раз, и для каждого его шага внутренний цикл снова выполняется n раз: n · n шагов.

Для небольших массивов квадратичная сложность вполне приемлема. Для 100 000 элементов это уже 10 миллиардов шагов — именно на этом программы начинают «зависать».


Все пары

Самая прямая задача на O(n²): соединить каждый элемент с каждым. 4 буквы дают 4 · 4 = 16 пар; 100 букв дали бы 10 000.

Построение всех пар

Внешний цикл выбирает $x, внутренний соединяет его с каждым $y. 4 элемента дают 16 пар — квадрат размера входных данных.

Prompt
Напиши PHP-скрипт с массивом a, b, c, d, который с помощью двух вложенных циклов выводит все пары букв (например, aa ab ac ad) — по одной строке на каждый элемент внешнего цикла — и подсчитывает пары. В конце выведи, сколько элементов образовали сколько пар.
Вывод: PHP-скрипт
Build every pair

Пузырьковая сортировка

Пузырьковая сортировка — классический квадратичный алгоритм: он многократно проходит по массиву и меняет местами соседние элементы, стоящие в неверном порядке. Большие значения «всплывают» к концу, по одному за проход.

Из-за двух вложенных циклов он выполняет примерно n²/2 сравнений. На нём отлично учиться — и плохо им пользоваться: встроенная в PHP функция sort() делает то же самое за O(n log n).

Сортировка двумя вложенными циклами

Сортировка 5 элементов требует 4 + 3 + 2 + 1 = 10 сравнений. Для 1 000 элементов их было бы около полумиллиона — тогда как сортировке с O(n log n) нужно около десяти тысяч.

Prompt
Напиши PHP-скрипт, который сортирует массив 5, 3, 8, 1, 4 методом пузырьковой сортировки — двумя вложенными циклами, меняющими местами соседние элементы, стоящие в неверном порядке, — и одновременно подсчитывает сравнения. Выведи отсортированный массив и число сравнений.
Вывод: PHP-скрипт
Sort with two nested loops

Поиск дубликатов медленным способом

Проверка каждого элемента со всеми элементами, идущими после него, — ещё один шаблон вложенных циклов: сравнение всех пар для поиска дубликата.

Это работает, но сложность равна O(n²). Страница «Пространственная сложность» в этой группе показывает стандартный приём, который делает такой поиск линейным: запоминать уже встреченные значения в ассоциативном массиве.

Поиск дубликата двумя циклами

Каждый элемент сравнивается со всеми последующими. Пара одинаковых значений 1 находится после 7 проверок; в худшем случае — когда дубликатов нет вовсе — выполняются все 15 проверок пар.

Prompt
Напиши PHP-скрипт, который находит повторяющееся значение в массиве 3, 1, 4, 1, 5, 9, сравнивая каждый элемент со всеми последующими в двух вложенных циклах и подсчитывая проверки. Когда дубликат найден, выведи значение и число проверок на этот момент.
Вывод: PHP-скрипт
Find a duplicate with two loops