Оценка сложности алгоритма

Big O нотация, или Как оценить сложность алгоритма

Что такое алгоритм

Алгоритм - набор действий (инструкция), который компьютер может выполнить и который приведёт к нужному нам результату.

Как измерить сложность алгоритма

Просто измерять время выполнения двух алгоритмов не вариант, ибо один алгоритм может быстрее обработать 10 чисел, но в задаче с 1кк чисел он окажется медленнее, так как 2-й алгоритм может быть лучше оптимизирован именно под работу с большим кол-вом чисел.
Приходится придумывать вариант посложнее, который поможет оценить работу алгоритма с разными объёмами данных. Нужно описать связь между кол-вом операций и элементов. В математике это позволяет сделать подобная функция


значение будет зависеть от значения по определённому правилу.


будет всегда в раза больше .


Зависимость может быть любой - главное, что есть инструмент, с помощью которого можно описать такую зависимость.

Например, мы можем сравнить:

Если - это зарплата, а - кол-во отработанных дней, мы и без калькулятора можно сделать выбор между этими двумя предложениями.
В нашем случае - кол-во действий, которые алгоритм должен совершить, а - кол-во элементов, которые он должен обработать.

Если возьмём простую зависимость:

то по такому описанию поймём, что алгоритм на каждый элемент выполняет по 2 действия. А значит, если нам надо будет обработать 100 элементов, алгоритм сделает это за 200 действий:

, и чаще используются в школьных задачах. Когда речь заходит об оценке сложности алгоритмов, принято использовать следующие обозначения:

- кол-во элементов;
- функция от кол-ва элементов (по сути, это и есть или ).

Буквы другие, но суть та же - они сразу позволяют понять, что речь идёт о задаче оценки сложности алгоритмов.


Типичные примеры O-нотации (сложности алгоритмов)

Никаких сложных точных уравнений писать не нужно. Есть несколько общих вариантов зависимости, которые позволяют примерно оценить скорость работы алгоритма. По сути, не столько важно конкретное кол-во действий алгоритма, сколько важен порядок роста.
То есть мы отвечаем на вопросы вида: «Если алгоритм обработает 10 элементов за X действий, во сколько раз больше действий ему понадобится на 1 000 элементов?».

Ниже по порядку возрастания сложности все варианты:

  •  - в этом случае у нас нет числа n, как нет и зависимости от кол-ва элементов. Такая оценка может быть, например, у алгоритмов, которые выполняют действие над одним элементом.
    Допустим, извлекают одну букву из строки. В строке может быть млрд букв, а может быть 10, но первую букву можно извлечь за одно действие.

  •  - может пугать, но достаточно просто запомнить, что эта оценка быстрее линейной зависимости. Если при линейной зависимости на 128 элементов мы потратим 128 действий, то при :
    - нам понадобится всего 7 действий.
    Кол-во действий будет расти с кол-вом элементов, но происходить это будет гораздо медленнее.

  •  - линейная оценка, самая простая (но не самая эффективная, как мы видели ранее).
    Сколько элементов - столько и действий.

  •  - пожалуй, самая длинная из вариантов, она говорит о том, что алгоритм работает медленнее, чем при линейной оценке. Можем пересчитать пример со 128 элементами:

    Получается значительная разница (и чем больше элементов - тем она будет существеннее).

  •  - квадратичная зависимость, она ещё более медленная, чем предыдущая. Если там мы умножали , здесь нам пришлось бы умножать на

  •  - самая медленная оценка из базовых - факториал от числа элементов, который надо обработать. Для обработки 128 элементов пришлось бы считать следующую цепочку:
    ~ - это число намного больше предыдущего большого числа.

Наглядно

Допустим, задача - разделить лист бумаги на 16/256/1024 прямоугольников.

Пусть компьютер выполняет 10 операций в секунду. Если мы выберем для решения задачи алгоритм со сложностью , то для получения 16 прямоугольников нам понадобится всего 4 операции, и они выполнятся за 0,4 с.


Алгоритмы, связанные со строками

python