В этой статье будет рассмотрено, как вы можете использовать библиотеки визуализации и программное обеспечение для определения сложностей среды для разных алгоритмов. Мы рассмотрим основное использование matplotlib
Для визуализации двухмерных участков и Numpy
Для вычисления линий наилучшего соответствия, а затем рассказать о том, как эти библиотеки можно использовать для определения их сложности времени выполнения либо через «угадание», либо путем сравнения графиков их времени выполнения с известными функциями (т.е. y =x
, y = 2^n
)
Если вы заинтересованы в загрузке кода, представленного в этой статье, пожалуйста, посетите Этот репозиторий на моем GitHub (Chroline/VisuizationRuntimes).
Сложность времени выполнения, более конкретно сложность времени выполнения Анализ , это измерение того, как «быстрый» может работать алгоритм как объем операций, которые он требует, увеличивается. Прежде чем мы погрузимся в визуализацию времени пробега разных алгоритмов, давайте посмотрим на пару основных примеров, чтобы объяснить концепцию.
Возьмите следующее Добавить
функция Он принимает два параметра, A
и b
и выполняет дополнение на A
и b
Анкет
def add(a, b): return a + b
При предоставлении любых двух параметров (1 и 2, 2 и 3, 29347 и 93648) количество операций не изменяется. Поэтому мы говорим, что алгоритм работает в постоянной или O (1)
, время.
Однако теперь рассмотрим следующее перестановки
функция Он принимает один основной параметр, строка
и печатает все перестановки этой строки.
def permutations(string, step = 0): if step == len(string): print "".join(string) for i in range(step, len(string)): string_copy = [c for c in string] string_copy[step], string_copy[i] =string_copy[i], string_copy[step] permutations(string_copy, step + 1)
Как вы могли себе представить, эта функция займет гораздо больше времени, чем предыдущая Добавить
функция; На самом деле, эта функция будет работать в так называемом Фактор Время, представленное как На!)
. Это потому, что как количество символов в строка
увеличивается, объем операций, необходимых для поиска всех перестановки, увеличивается факторно.
Сравнивая время выполнения двух функций визуально, вы заметите резкий контраст на графиках, которые они производят. Для Добавить
Функция, вы бы соблюдали плоскую линию, так как вход функции не влияет на объем операций, требуемых функцией. Однако для перестановки
Функция, вы бы соблюдали линию, которая резко всплывает вверх (наклон линии приблизится к бесконечности), потому что объем операций увеличивается факторно с увеличением размера входа.
Теперь, когда мы рассмотрели основы анализа сложности времени выполнения, мы можем начать процесс написания кода, чтобы визуализировать время выполнения различных алгоритмов.
Перед запуском каких -либо визуализаций мы должны сначала импортировать необходимые библиотеки и инициализировать их.
matplotlib
библиотека, которая будет создавать и отображать графикиNumpy
библиотека, которая состоит из многочисленных математических функцийTimeit
это библиотека, которую мы будем использовать во времени, как долго каждый звонок в алгоритм принимаетМатематика
Основная библиотека математики Pythonслучайный
Основная библиотека рандомизации Python
import matplotlib.pyplot as plt import numpy as np import timeit import math import random plt.rcParams['figure.figsize'] = [10, 6] # set size of plot
Ниже приведены некоторые сегменты кода, которые демонстрируют, как использовать matplotlib
и Numpy
Анкет
Сумма функция
Питон сумма
Функция вычисляет сумму всех элементов предоставленного Итерабильный
Анкет Эта функция реализует алгоритм с O (n)
Сложность времени выполнения.
Чтобы проверить это, мы будем использовать Linspace
Метод из Numpy
Библиотека для создания итерабильных с 50 равномерно распределенными значениями в диапазоне от 10 до 10 000. График, хотя и не совершенно прямой сюжет, иллюстрирует это.
ns = np.linspace(10, 10_000, 50, dtype=int) ts = [timeit.timeit('sum(range({}))'.format(n), number=100) for n in ns] plt.plot(ns, ts, 'or')
Мы можем добавить линию наилучшего соответствия (с помощью функции 4-й степени), чтобы дополнительно иллюстрировать это. График никогда не будет совершенно прямой, но он должен приблизиться.
degree = 4 coeffs = np.polyfit(ns, ts, degree) p = np.poly1d(coeffs) plt.plot(ns, ts,'or') plt.plot(ns, [p(n)for nin ns],'-b')
Список индексации
Получение элемента из списка (индексация списка) работает с O (1)
Сложность времени выполнения, что означает, что количество элементов в списке не влияет на то, как долго требуется алгоритм. Как это представлено в графике?
lst = list(range(1_000_000)) ns = np.linspace(0, len(lst), 1000, endpoint=False, dtype=int) ts = [timeit.timeit('_ = lst[{}]'.format(n), globals=globals(), number=10000) for nin ns] plt.plot(ns, ts,'or') degree = 4 coeffs = np.polyfit(ns, ts, degree) p = np.poly1d(coeffs) plt.plot(ns, [p(n)for nin ns],'-b')
Теперь мы рассмотрим графики, созданные следующими алгоритмами:
- Линейный поиск
- Бинарный поиск
- вставка сортировки
Линейный поиск
Линейный поиск имеет сложность времени выполнения O (n)
, который будет представлен приблизительно прямой линией.
Красные сюжеты Продемонстрировать поиск элемента в перетасованном, Синие сюжеты Продемонстрировать поиск элемента, которого нет в списке.
Линия, наиболее подходящая для красных участков, обычно будет меньше, чем у синих графиков, потому что поиск элемента, которого нет в списке требует итерации по всему списку.
## searches for an item in a list def contains(lst, x): for y in lst: if x == y: return True return False ns = np.linspace(10, 10_000, 100, dtype=int) # red plots ts = [timeit.timeit('contains(lst, 0)', setup='lst=list(range({})); random.shuffle(lst)'.format(n), globals=globals(), number=100) for n in ns] plt.plot(ns, ts, 'or') # line of best fit for red plots degree = 4 coeffs = np.polyfit(ns, ts, degree) p = np.poly1d(coeffs) plt.plot(ns, [p(n) for n in ns], '-r') # blue plots ts = [timeit.timeit('contains(lst, -1)', setup='lst=list(range({}))'.format(n), globals=globals(), number=100) for n in ns] plt.plot(ns, ts, 'ob') # line of best fit for blue plots degree = 4 coeffs = np.polyfit(ns, ts, degree) p = np.poly1d(coeffs) plt.plot(ns, [p(n) for n in ns], '-b')
Бинарный поиск
Бинарный поиск работает с O (log n)
Сложность времени выполнения.
# searches for an item in a list using linear search def contains(lst, x): lo = 0 hi = len(lst)-1 while lo <= hi: mid = (lo + hi) // 2 if x < lst[mid]: hi = mid - 1 elif x > lst[mid]: lo = mid + 1 else: return True else: return False ns = np.linspace(10, 10_000, 100, dtype=int) ts = [timeit.timeit('contains(lst, 0)', setup='lst=list(range({}))'.format(n), globals=globals(), number=1000) for n in ns] plt.plot(ns, ts, 'or') degree = 4 coeffs = np.polyfit(ns, ts, degree) p = np.poly1d(coeffs) plt.plot(ns, [p(n) for n in ns], '-b')
Выше это то, как должен выглядеть график в почти идеальном моделировании. Как видите, есть некоторые выбросы, и в идеальном симуляции линия наилучшего соответствия будет идентична логарифмической функции.
Вставка сортировки
Какая сложность времени выполнения имеет сортирование вставки? Мы можем использовать графики его времени выполнения и сравнить эти графики с графиками известных времен пробежки, чтобы определить, какое самое близкое совпадение.
def insertion_sort(lst): for i in range(1, len(lst)): for j in range(i, 0, -1): if lst[j-1] > lst[j]: lst[j-1], lst[j] = lst[j], lst[j-1] else: break # 15 values ns = np.linspace(100, 2000, 15, dtype=int) ts = [timeit.timeit('insertion_sort(lst)', setup='lst=list(range({})); random.shuffle(lst)'.format(n), globals=globals(), number=1) for n in ns] plt.plot(ns, ts, 'or'); degree = 4 coeffs = np.polyfit(ns, ts, degree) p = np.poly1d(coeffs) plt.plot(ns, [p(n) for n in ns], '-r')
Теперь мы можем сравнить этот график с графиками различных времен пробежки, чтобы в конечном итоге определить, что наиболее схоже и каким есть сортировка сложности выполнения.
Красные сюжеты Представляю O (log n)
, Синие сюжеты Представляю O (n^2)
, Зеленые сюжеты Представляю O (2^n)
Анкет
# y = log x # vertically stretched 1000x ns = range(1, 100) ts = [math.log(n, 2) * 1000 for n in ns] plt.plot(ns, ts, 'or'); # y = x^2 ns = range(1, 100) ts = [(n*n) for n in ns] plt.plot(ns, ts, 'ob'); # y = 2^x # vertically stretched 20x # horizontally compressed 1x ns = range(1, 10) ts = [math.pow(2, n)*20 for n in ns] plt.plot(ns, ts, 'og');
Основываясь на этих графиках, можно с уверенностью предположить, что вставка сортируется в O (n^2)
время.
Можем ли мы использовать визуализацию времени загадочных функций, чтобы угадать их сложности времени выполнения?
Тайная функция № 1
def f(l: list, val): # l is a python list with n items d = {} for i in range(len(l)): d[l[i]] = i return d[val] ns = range(5, 2000) ts = [timeit.timeit('f(lst, {})'.format(n-1), setup='lst=list(range({})); random.shuffle(lst)'.format(n), globals=globals(), number=1) for n in ns] plt.plot(ns, ts, 'or'); degree = 4 coeffs = np.polyfit(ns, ts, degree) p = np.poly1d(coeffs) plt.plot(ns, [p(n) for n in ns], '-b')
Даже не сравнивая этот график с графиками возможного времени выполнения, мы уже можем с уверенностью предположить, что эта функция работает в На)
время выполнения.
Тайная функция № 2
def g(l): # l is a python list of integers of length n pairs = [ (i,j) for i in range(len(l)) for j in range(len(l)) if i < j ] result = [] for (i,j) in pairs: if l[i] == l[j]: result.append((i,j)) return result ns = range(5, 200) ts = [timeit.timeit('g(lst)', setup='lst=list(range({}))'.format(n), globals=globals(), number=1) for n in ns] plt.plot(ns, ts, 'or') degree = 4 coeffs = np.polyfit(ns, ts, degree) p = np.poly1d(coeffs) plt.plot(ns, [p(n) for n in ns], '-b')
Этот график выглядит очень похоже на тот, который для вставки, поэтому мы можем определить, что эта функция имеет сложность времени выполнения O (n^2)
Анкет
Тайная функция № 3
def h(n): if n <= 1: return n else: return h(n-1) + h(n-2) ns = range(5, 30) ts = [timeit.timeit('h({})'.format(n), globals=globals(), number=1) for n in ns] plt.plot(ns, ts, 'or')
Эта функция более неоднозначна, чем предыдущие два. Очевидно, что его время выполнения должно быть больше, чем На)
По мере увеличения наклона как n
увеличивается. Давайте рассмотрим графики Runtime O (n^2)
в красный и O (2^n)
в синий Анкет
# y = n^2 # vertically stretched 20x ns = range(5, 30) ts = [n*n*20000 for n in ns] plt.plot(ns, ts, 'or') # y = 2^n # vertically compressed 50x ns = range(5, 30) ts = [math.pow(2, n)/50 for n in ns] plt.plot(ns, ts, 'ob')
График времени выполнения таинственной функции № 3 больше напоминает синие графики, поэтому, следовательно, сложность времени выполнения таинственной функции № 3 – O (2^n)
Анкет
Используя эти библиотеки визуализации, мы можем определить сложности времени выполнения функций и алгоритмов, сравнивая их с графиками/графиками известного времени выполнения (то есть, сравнивая графики внедрения сортировки сортировки с y = n^2
). В дополнение к определению сложности выполнения, эта методология может быть использована для сравнения скоростей разных алгоритмов друг с другом. Имея всего несколько строк кода, вы можете быстро увидеть скорость, с которой выбранные вами алгоритмы будут работать с большими наборами данных!
- Учебник Pyplot-Matplotlib 3.4.2 Документация
- Numpy.polyfit-Numpy v1.20 Руководство
- Программа Python для отображения последовательности Fibonacci с использованием Recursion (Programiz.com)
- Как найти все возможные перестановки данной строки в Python? (Turning Spoct.com)
- 8 временных сложностей, которые должен знать каждый программист | Блог Адриан Мехия
Оригинал: “https://dev.to/chroline/visualizing-algorithm-runtimes-in-python-f92”