Edycja: Ważna wersja w wersji 3.
Ponieważ nigdy nie prowadziłem zajęć, nie sądzę, żebym mógł przekonująco twierdzić o tym, czego powinniśmy uczyć. Niemniej jednak oto, co o tym myślałem.
Istnieją naturalne przykłady, w których napisana „sztuczka z limitem”, jak jest napisana, nie może być zastosowana. Załóżmy na przykład, że zaimplementujesz „wektor o zmiennej długości” (jak wektor <T> w C ++) za pomocą tablicy o stałej długości z podwojeniem rozmiaru (to znaczy za każdym razem, gdy masz zamiar przekroczyć rozmiar tablicy, ponownie przydziel tablicę dwa razy większą niż teraz i skopiuj wszystkie elementy). Rozmiar S ( n ) tablicy, gdy przechowujemy n elementów w wektorze, jest najmniejszą potęgą o wartości 2 większej lub równej n . Chcemy powiedzieć, że S ( n ) = O ( n ), ale użycie „sztuczki z limitem”, jak jest zapisane jako definicja, nie pozwoli nam na to, ponieważ S ( n) / n oscyluje gęsto w przedziale [1,2). To samo dotyczy Ω () i Θ ().
Jako nieco odrębną kwestię, kiedy używamy tych notacji do opisania złożoności algorytmu, myślę, że twoja definicja Ω () jest czasami niewygodna (chociaż myślę, że ta definicja jest powszechna). Bardziej wygodne jest zdefiniowanie, że f ( n ) = Ω ( g ( n )) wtedy i tylko wtedy, gdy limsup f ( n ) / g ( n )> 0. Jest tak, ponieważ niektóre problemy są trywialne dla nieskończenie wielu wartości n ( np. idealny problem z obróbką na wykresie z nieparzystą liczbą n wierzchołków). To samo dotyczy Θ () i ω ().
Dlatego osobiście uważam, że następujące definicje są najwygodniejsze w opisie złożoności algorytmu: dla funkcji f , g : ℕ → ℝ > 0 ,
- f ( n ) = o ( g ( n )) wtedy i tylko wtedy, gdy limsup f ( n ) / g ( n ) = 0. (Jest to równoważne z lim f ( n ) / g ( n ) = 0.)
- f ( n ) = O ( g ( n )) wtedy i tylko wtedy, gdy limsup f ( n ) / g ( n ) <∞.
- f ( n ) = Θ ( g ( n )) wtedy i tylko wtedy, gdy 0 <limsup f ( n ) / g ( n ) <∞.
- f ( n ) = Ω ( g ( n )) wtedy i tylko wtedy, gdy limsup f ( n ) / g ( n )> 0. (Jest to równoważne z tym, że f ( n ) nie jest o ( g ( n )).)
- f ( n ) = ω ( g ( n )) wtedy i tylko wtedy, gdy limsup f ( n ) / g ( n ) = ∞. (Jest to równoważne z tym, że f ( n ) nie jest O ( g ( n )).)
lub równoważnie
- f ( n ) = o ( g ( n )) wtedy i tylko wtedy, gdy dla każdego c > 0, dla wystarczająco dużego n , f ( n ) ≤ c ⋅ g ( n ).
- f ( n ) = O ( g ( n )) wtedy i tylko wtedy, gdy dla niektórych c > 0, dla wystarczająco dużego n , f ( n ) ≤ c ⋅ g ( n ).
- f ( n ) = Θ ( g ( n )) wtedy i tylko wtedy, gdy f ( n ) = O ( g ( n )) if ( n ) = Ω ( g ( n )).
- f ( n ) = Ω ( g ( n )) wtedy i tylko wtedy, gdy dla niektórych d > 0, dla nieskończenie wielu n , f ( n ) ≥ d ⋅ g ( n ).
- f ( n ) = ω ( g ( n )) wtedy i tylko wtedy, gdy dla każdego d > 0, dla nieskończenie wielu n , f ( n ) ≥ d ⋅ g ( n ).
Ale nie wiem, czy jest to powszechna praktyka, czy nie. Nie wiem też, czy nadaje się do nauczania. Problem polega na tym, że czasami chcemy zamiast tego zdefiniować Ω () za pomocą liminf (jak w pierwszej definicji). Na przykład, kiedy mówimy „Prawdopodobieństwo błędu tego randomizowanego algorytmu wynosi 2 Ω ( n ) ”, nie mamy na myśli, że prawdopodobieństwo błędu jest wykładniczo małe tylko dla nieskończenie wielu n !