Изменить: Основная редакция в редакции 3.
Поскольку я никогда не преподавал на уроках, я не думаю, что могу что-либо убедительно заявить о том, чему мы должны учить. Тем не менее, вот что я подумал об этом.
Существуют естественные примеры, когда «предельная уловка», как написано, не может быть применена. Например, предположим, что вы реализуете «вектор переменной длины» (например, vector <T> в C ++), используя массив фиксированной длины с удвоением размера (то есть каждый раз, когда вы собираетесь превысить размер массива, вы перераспределить массив в два раза больше, чем сейчас, и скопировать все элементы). Размер S ( n ) массива, когда мы храним n элементов в векторе, является наименьшей степенью 2, большей или равной n . Мы хотим сказать, что S ( n ) = O ( n ), но использование «предельного трюка», как написано в определении, не позволит нам сделать это, потому что S ( n) / n плотно колеблется в диапазоне [1,2). То же самое относится к Ω () и Θ ().
В качестве отдельного вопроса, когда мы используем эти обозначения для описания сложности алгоритма, я думаю, что ваше определение Ω () иногда неудобно (хотя я предполагаю, что это определение является общим). Удобнее определить, что f ( n ) = Ω ( g ( n )) тогда и только тогда, когда limsup f ( n ) / g ( n )> 0. Это связано с тем, что некоторые задачи тривиальны для бесконечного числа значений n ( например, проблема идеальной обработки на графе с нечетным числом n вершин). То же самое относится к Θ () и ω ().
Поэтому лично я считаю, что следующие определения наиболее удобно использовать для описания сложности алгоритма: для функций f , g : ℕ → ℝ > 0 ,
- f ( n ) = o ( g ( n )) тогда и только тогда, когда limsup f ( n ) / g ( n ) = 0. (Это эквивалентно lim f ( n ) / g ( n ) = 0.)
- f ( n ) = O ( g ( n )) тогда и только тогда, когда limsup f ( n ) / g ( n ) <∞.
- f ( n ) = Θ ( g ( n )) тогда и только тогда, когда 0 <limsup f ( n ) / g ( n ) <∞.
- f ( n ) = Ω ( g ( n )) тогда и только тогда, когда limsup f ( n ) / g ( n )> 0. (Это эквивалентно тому, что f ( n ) не является o ( g ( n )).)
- f ( n ) = ω ( g ( n )) тогда и только тогда, когда limsup f ( n ) / g ( n ) = ∞. (Это эквивалентно тому, что f ( n ) не является O ( g ( n )).)
или эквивалентно,
- f ( n ) = o ( g ( n )) тогда и только тогда, когда для каждого c > 0, для достаточно большого n , f ( n ) ≤ c ⋅ g ( n ).
- f ( n ) = O ( g ( n )) тогда и только тогда, когда для некоторого c > 0, для достаточно большого n , f ( n ) ≤ c ⋅ g ( n ).
- f ( n ) = Θ ( g ( n )) тогда и только тогда, когда f ( n ) = O ( g ( n )) и f ( n ) = Ω ( g ( n )).
- f ( n ) = Ω ( g ( n )) тогда и только тогда, когда для некоторого d > 0, для бесконечного числа n , f ( n ) ≥ d ⋅ g ( n ).
- f ( n ) = ω ( g ( n )) тогда и только тогда, когда для каждого d > 0, для бесконечно многих n , f ( n ) ≥ d ⋅ g ( n ).
Но я не знаю, является ли это обычной практикой или нет. Также я не знаю, подходит ли оно для обучения. Проблема в том, что мы иногда хотим определить Ω () вместо liminf (как вы делали в первом определении). Например, когда мы говорим «Вероятность ошибки этого рандомизированного алгоритма составляет 2 -Ω ( n ) », мы не имеем в виду, что вероятность ошибки экспоненциально мала только для бесконечного числа n !