Большой O: верхняя граница
«Большой O» ( ), безусловно, самый распространенный. Когда вы анализируете сложность алгоритма, в большинстве случаев важно иметь некоторую верхнюю границу для того, насколько быстро время выполнения увеличивается с увеличением размера входных данных. По сути, мы хотим знать, что выполнение алгоритма не займет «слишком много времени». Мы не можем выразить это в фактических единицах времени (секундах), потому что это будет зависеть от точной реализации (от того, как написана программа, насколько хорош компилятор, насколько быстрым является процессор машины,…). Таким образом, мы оцениваем то, что не зависит от таких деталей, а именно, сколько времени потребуется для запуска алгоритма, когда мы вводим больший вход. И нам в основном важно, когда мы можем быть уверены, что программа выполнена, поэтому мы обычно хотим знать, что она займет столько-то времени или меньше.О
Сказать, что алгоритм имеет время выполнения для входного размера означает, что существует некоторая постоянная такая, что алгоритм завершает самое большее шагов, т.е. время выполнения алгоритма растет максимально быстро, как (до коэффициента масштабирования). Отмечая время выполнения алгоритма для входного размера , неофициально означает, что точностью до некоторого коэффициента масштабирования.n K KO ( f( н ) )NКf T ( n ) n O ( n ) T ( n ) ≤ f ( n )Ке( н )еT( н )NO ( n )T( n ) ≤ f( н )
Нижняя граница
Иногда полезно иметь больше информации, чем верхняя граница. - это обратное к : оно выражает то, что функция растет по крайней мере так же быстро, как и другая. означает, что для некоторой константы или, если говорить неформально, вверх к некоторому коэффициенту масштабирования.O T ( n ) = Ω ( g ( n ) ) T ( N ) ≥ K ′ g ( n ) K ′ T ( n ) ≥ g ( n )ΩОT( n ) = Ω ( г( н ) )T(N)≥K′g(n)K′T(n)≥g(n)
Когда время выполнения алгоритма может быть точно определено, объединяет и : это выражает то, что скорость роста функции известна, вплоть до коэффициента масштабирования. означает, что для некоторых констант и . Неформально говоря, точностью до некоторого коэффициента масштабирования.O Ω T ( n ) = Θ ( h ( n ) ) K h ( n ) ≥ T ( n ) ≥ K ′ h ( n ) K K ′ T ( n ) ≈ h ( n )ΘOΩT(n)=Θ(h(n))Kh(n)≥T(n)≥K′h(n)KK′T(n)≈h(n)
Дальнейшие соображения
«Маленькие» и используются гораздо реже в анализе сложности. Маленькая сильнее, чем большая ; где указывает на рост, который происходит не быстрее, указывает на то, что рост строго медленнее. И наоборот, указывает на строго более быстрый рост.ω о O O O ωoωoOOoω
Я был немного неформальным в обсуждении выше. В Википедии есть небольшие определения и более математический подход.
Имейте в виду, что использование знака равенства в и т. П. Является неправильным. Строго говоря, - это набор функций переменной , и мы должны написать .O ( f ( n ) ) n T ∈ O ( f )T(n)=O(f(n))O(f(n))nT∈O(f)
Пример: некоторые алгоритмы сортировки
Поскольку это довольно сухо, позвольте мне привести пример. Большинство алгоритмов сортировки имеют квадратичное время выполнения в наихудшем случае, т. Е. Для входа размера время выполнения алгоритма равно . Например, сортировка выбора имеет время выполнения , потому что выбор го элемента требует сравнений, в общей сложности сравнений. На самом деле, число сравнений всегда ровно , которое растет как . Таким образом, мы можем быть более точными относительно временной сложности выбора сортировки: это .O ( n 2 ) O ( n 2 ) k n - k n ( n - 1 ) / 2 n ( n - 1 ) / 2 n 2 Θ ( n 2 )nO(n2)O(n2)kn−kn(n−1)/2n(n−1)/2n2Θ(n2)
Теперь возьмите сортировку слиянием . Сортировка слиянием также квадратична ( ). Это правда, но не очень точно. На самом деле сортировка слиянием имеет время выполнения в худшем случае. Как и сортировка выбора, рабочий процесс сортировки слиянием, по существу, не зависит от формы ввода, и его время выполнения всегда равно точностью до постоянного множительного множителя, т.е. это .O ( nO(n2)nO(nlg(n))Θ ( nnlg(n)Θ(nlg(n))
Далее рассмотрим быструю сортировку . Быстрая сортировка сложнее. Это, конечно, . Кроме того, наихудший случай быстрой сортировки является квадратичным: наихудший случай - . Однако лучший случай быстрой сортировки (когда вход уже отсортирован) является линейным: лучшее, что мы можем сказать для нижней границы быстрой сортировки в целом, это . Я не буду повторять здесь доказательство, но средняя сложность быстрой сортировки (среднее значение по всем возможным перестановкам входных данных) равна .Θ ( n 2 ) Ω ( n ) Θ ( nO(n2)Θ(n2)Ω(n)Θ(nlg(n))
Существуют общие результаты о сложности алгоритмов сортировки в общих настройках. Предположим, что алгоритм сортировки может сравнивать только два элемента одновременно, с результатом да или нет (либо либо ). Тогда очевидно, что время выполнения любого алгоритма сортировки всегда равно (где - количество элементов для сортировки), потому что алгоритм должен хотя бы один раз сравнить каждый элемент, чтобы узнать, где он будет соответствовать. Эта нижняя граница может быть достигнута, например, если входные данные уже отсортированы, и алгоритм просто сравнивает каждый элемент со следующим и сохраняет их в порядке (это сравнений). Что менее очевидно, так это то, что максимальное время работы обязательноx > y Ω ( n ) n n - 1 Ω ( nx≤yx>yΩ(n)nn−1Ω(nlg(n)) . Вполне возможно, что алгоритм иногда делает меньше сравнений, но должна быть некоторая постоянная такая, что для любого входного размера существует хотя бы один вход, на котором алгоритм делает больше, чем сравнения. Идея доказательства состоит в том, чтобы построить дерево решений алгоритма, т.е. следовать решениям, которые алгоритм принимает из результатов каждого сравнения. Поскольку каждое сравнение возвращает результат «да» или «нет», дерево решений представляет собой двоичное дерево. Естьвозможные перестановки входных данных, и алгоритм должен различать их все, поэтому размер дерева решений равенKnKnlg(n)n!n!, Поскольку дерево является бинарным деревом, для соответствия всем этим узлам требуется глубина . Глубина - это максимальное количество решений, которые принимает алгоритм, поэтому выполнение алгоритма включает в себя как минимум столько сравнений: максимальное время выполнения равно .Θ(lg(n!))=Θ(nlg(n))Ω(nlg(n))
¹ Или другое потребление ресурсов, например, объем памяти. В этом ответе я рассматриваю только время выполнения.