Cуществуют определённые правила при оценке асимптотической сложности:
Постоянные множители и слагаемые можно опускать.
Многочлен более высокой степени растет быстрее.
Экспонента растёт быстрее многочлена.
Многочлен растёт быстрее логарифма.
Слагаемые, которые растут медленнее, можно опускать.
Чтобы понять, что одна функция асимптотически меньше другой, удобно разделить одну на другую и посмотреть на график того, что получилось.
Попробуем показать, что n5=O(2n). Получим дробь 2nn5.
Совсем не очевидно, что будет происходить с этим отношением по мере роста n.
Однако если построить график функции f(n)=2nn5, можно посмотреть, как будет вести себя функция при больших значениях аргумента n.
По графику видно, что отношение стремится к нулю. Это значит, что числитель намного меньше знаменателя. То есть n5 по мере увеличения n растет медленнее, чем 2n. Поэтому n5=O(2n).
Вот еще несколько примеров к правилам выше.
Правило 2: многочлен более высокой степени растет быстрее:
По этому графику также видно, что отношение стремится к нулю. Значит, что n2=O(n3).
Правило 4: многочлен растёт быстрее логарифма
Можно сделать вывод, что nlogn=O(n2).
Важно отметить, что основание логарифма обычно не учитывают при оценке «O» большого. Вот почему:
«O» большое — мощный инструмент в руках программиста.
Следующие функции часто встречаются на практике при анализе сложности алгоритмов.
На картинке они расположены в порядке увеличения скорости роста.
Рассмотрим фрагмент кода. Он не решает какую-то практическую задачу. Цель примера — показать, как оценивать общую эффективность алгоритма, части которого имеют разную вычислительную сложность.
Скопировать кодPYTHON
defsome_function(array, num):
max_elem = max(array) # определяем максимальный элемент в массиве
b = max_elem / 2
array.sort() # сортируем массив
result = []
for i in range(0, len(arr) - 2): # тройной цикл по длине массиваfor j in range(i, len(arr) - 1):
for k in range(j, len(arr)):
# do something# ...
_sum = arr[i] + arr[j] + arr[k]
if _sum > num:
result.append(_sum)
# ...for item in result:
if item > b:
print(item)
Оценим сложность алгоритма T(n). В данном случае n — длина входного массива array.
Если для некоторых операций непонятно, почему сложность именно такая, ничего страшного. Оценке сложности операций и алгоритмов для разных структур данных посвящены отдельные уроки. Пока можно просто поверить, что, например, сложность сортировки — O(nlogn).
Перейдём к оценке.
Сначала определяется максимальный элемент в массиве. Для этого нужно просмотреть все элементы. Сложность этой операции O(n). T(n)=n.
Далее массив сортируется. Сложность этой операции будет O(nlogn). T(n)=n+nlogn.
После этого в коде — тройной цикл по длине массива. На каждой итерации цикла происходит подсчёт суммы, сравнение и добавление элемента в массив, если условие выполнено. Но эти операции добавляют к сложности лишь константный множитель. То есть тройной цикл суммарно добавляет к сложности O(n3). T(n)=n+nlogn+n3.
После выхода из тройного цикла мы проходим по массиву result. В нём будет максимум n элементов. Для каждого элемента производится операция сравнения и, в случае выполнения условия, вывод на экран. Эти операции также добавляют к сложности константный множитель. Таким образом, последний участок кода суммарно добавляет к сложности алгоритма O(n). T(n)=n+nlogn+n3+n.
Получили, что T(n)=n3+nlogn+2n.
n3 растет быстрее, чем nlogn и 2n.
То есть, сложность алгоритма будет O(n3).
Вы сможете потренироваться и лучше понять правила, выполняя задания.
В программе вы видите фрагмент кода.
Скопировать кодPYTHON
for i in range(len(input_list)):
for j in range(len(input_list)):
if i[i] > i[j] + 1:
# далее следует код тела условной конструкции
Выберите верное утверждение:
Есть алгоритм: пройти по каждому элементу входного массива, возвести его в квадрат, сравнить результат со значением переменной a. Если результат окажется больше a, добавить элемент в новый массив. Какая у этого алгоритма сложность?
Какая вычислительная сложность у алгоритма, представленного фрагментом кода?
Скопировать кодPYTHON
for i in range(len(input_string)):
if input_string[i] == 'a':
cnt += 1
...
Отметьте, верно ли каждое утверждение:
Выведите номера функций в порядке увеличения асимптотической сложности (через пробел):