« poprzedni punkt   następny punkt »


6. Złożoność asymptotyczna 

Złożoność algorytmu zdefiniowaliśmy jako funkcję rozmiaru danych. Istotną informacją zawartą w tej funkcji jest jej zachowanie asymptotyczne, gdy rozmiar danych dąży do nieskończoności. Jest rzeczą zrozumiałą, że dla danych niewielkich rozmiarów, metoda obliczeń nie jest tak ważna, jak dla dużych danych, gdy nawet drobne zmiany wielkości danych powodują ogromne zmiany  w poniesionym koszcie.

Co więcej, dla dużych n nie jest też istotne, czy algorytm wykonuje n, czy n+5 operacji dominujących. Nawet stały współczynnik nie ma wielkiego znaczenia: jeśli jakiś algorytm wykonuje n2 operacji, a inny 2n2, to ich szybkość wzrostu do nieskończoności jest w przybliżeniu taka sama.

Definicja 6.1 Notacja asymptotyczna, wielkie O.

Niech f i g będą dwoma funkcjami ze zbioru liczb naturalnych w zbiór liczb rzeczywistych dodatnich, f, g : N ® R+. Powiemy, że funkcja g jest co najwyżej rzędu f, w skrócie g = O(f), wtedy i tylko wtedy, gdy dla pewnej stałej c i dla prawie wszystkich n, wartości funkcji g można oszacować z góry przez wartości funkcji f pomnożone przez stałą c,

g = O(f) wttw ($c>0)($n0ÎN)("n>n0)  g(n) £ c ´ f(n)

Rozważmy dla przykładu trzy funkcje f(n) = 10-6 n , g(n) = 106 n + 1000, h(n) = n2 + 3n +1. Na mocy przyjętej definicji, zarówno funkcję f jak i funkcję g można oszacować z góry przez funkcję  liniową n,

10-6 n = O(n)  oraz   106 n + 1000 = O(n).

Obie równości są spełnione dla dowolnych liczb naturalnych  i, na przykład, dla stałej c=1, w pierwszym przypadku, a stałej  c=2´106, w drugim przypadku.  Funkcji h nie można oszacować z góry przez funkcję g, gdyż zawsze znajdzie się dostatecznie duże n, że wartość h(n) będzie większa niż g(n), niezależnie od wyboru stałej c. Rzeczywiście, jeśli ustalimy c>0, to dla n > (c+1)106 mamy

c106 n + 1000 < (c+1) 106 n <  n2 < n2 + 3n + 1.

Obie funkcje f i g można natomiast  oszacować z góry przez funkcję h: funkcja kwadratowa rośnie do nieskończoności szybciej niż dowolna funkcja liniowa.

10-6 n < 106 n + 1000 < 106 (n+1) < n(n+1) < c (n2 + 3n + 1 ) dla stałej c=1 i dla n> 106 .

Wszystkie trzy funkcje można też oszacować przez dowolny wielomian rzędu wyższego niż 1. Oczywiście, im wyższy stopień tego wielomiany, tym mniej dokładne jest to oszacowanie.

Zauważmy, że dla dużych n,  ani stały składnik, ani nawet stały współczynnik multiplikatywny nie mają wielkiego znaczenia. Jeśli jakiś algorytm wykonuje c1´ n + c2  operacji, a inny n2, to  niezależnie od stałych c1 i c2, algorytm o złożoności c1´n + c2 będzie lepszy dla dostatecznie dużych n.

Zauważmy jeszcze proste własności notacji asymptotycznej, które przydadzą się nam przy szacowaniu kosztów algorytmów omawianych w tym wykładzie.

Lemat 6.1

Dla dowolnych funkcji  f, g, h  określonych w zbiorze liczb naturalnych i o wartościach w zbiorze liczb rzeczywistych dodatnich,

Dowód lematu wynika natychmiast z definicji notacji wielkie O. Rozważmy dla przykładu  drugą własność. Niech f=O(h) i g = O(h). Istnieją więc dodatnie stałe c1 i c2 oraz liczby naturalne n1 i n2 takie że

 f(n) £ c1 ´ h(n),  dla  n ³ n1   i  g(n) £ c2 ´ h(n), dla n ³ n2.

Przyjmując jako n0 = max(n1, n2) oraz c = c1+ c2, otrzymamy  f(n) + g(n) £ c1 ´ h(n) + c2 ´ h(n) = c ´ h(n) dla wszystkich n ³ n0, co dowodzi, że f + g = O(h).

Analogicznie do oszacowania górnego, wprowadza się oszacowanie dolne asymptotycznego rzędu funkcji.

Definicja 6.2 Notacja asymptotyczna, oszacowanie dolne.

Niech f i g będą funkcjami ze zbioru liczb naturalnych w zbiór liczb rzeczywistych dodatnich, f, g : N ® R+. Powiemy, że funkcja g jest co najmniej rzędu f, w skrócie g = W(f), wtedy i tylko wtedy, gdy istnieje dodatnia stała c, że dla prawie wszystkich n, wartości funkcji g można oszacować z dołu  przez wartości funkcji f pomnożone przez stałą c,

g = W(f) wttw ($c>0)($n0ÎN)("n>n0)   c ´ f(n) £ g(n)

Rozważmy jeszcze raz funkcje z poprzedniego przykładu. Jak wynika z poprzednich rozważań, funkcję h(n) = n2 + 3n +1 możemy oszacować z dołu przez funkcję g(n) = 106 n + 1000, a tym bardziej przez funkcję f. Nieco wbrew intuicji, funkcję f można oszacować z dołu przez funkcję g przyjmując odpowiednią wartość dla stałej c,

c(106 n + 1000)  < 10-6 n  dla wszystkich n naturalnych i c = 10-7 .

Nie jest natomiast możliwe oszacowanie funkcji g z dołu przez funkcję h. Oczywiście, dla wszystkich k>2 mamy też nk = O(h(n)).

Definicja 6.3 Rząd funkcji.

Funkcje  f i g takie, że f, g : N ® R+ mają asymptotycznie ten sam rząd wielkości, co oznaczamy f = Q(g), wtedy i tylko wtedy, gdy

g = O(f) oraz f = O(g).

Na mocy tej definicji każda z funkcji  n3+ 100n, 100n3 , (1/100)n3, ( n5 +n4 +15 n)/ (n2 +10n + 6) ma taki sam rząd jak funkcja n3

Warto zapamiętać, że rzędy wielkości asymptotycznej znanych funkcji: lg n, n, n lg n, n2, n3, 2n, 3n, nn  ściśle rosną: każdą funkcja w tym ciągu może być z góry oszacowana przez funkcję następną, a żadna z nich nie może być z góry oszacowana przez funkcję poprzednią.

Następujący lemat pozwala ustalić asymptotyczny rząd funkcji metodami analizy matematycznej.

Lemat 6.2

Niech f i g będą funkcjami określonymi na liczbach naturalnych, o wartościach w zbiorze liczb rzeczywistych dodatnich, oraz niech limn®¥ f(n)/g(n) = c. Wtedy

Korzystając z tego lematu łatwo udowodnimy, że funkcja 2n ma inny rząd niż funkcja 3n. Chociaż obie rosną do nieskończoności bardzo szybko, to asymptotyczny rząd  funkcji 2n jest ściśle mniejszy niż rząd funkcji 3n,

limn®¥ (2n /3n) = limn®¥ (2/3)n = 0.

Podobnie funkcja lg n! rośnie do nieskończoności wolniej niż funkcja kwadratowa n2.  Rzeczywiście, ponieważ lgn! może być przedstawiony jako suma lg 1 + lg 2 + ... + lg (n-1) + lg n, zatem mamy oszacowanie

(lg n)/n2 £  (lg n!)/ n2  £ (n lg n)/ n2.

Ponieważ obie funkcje (lg n)/n2  i (n lg n)/n2 dążą do zera przy n zmierzającym do nieskończoności, zatem limn®¥ ( (lg n!)/ n2) = 0, co  na mocy lematu dowodzi, że log n! = O(n2) oraz log n! ¹ Q(n2).

Definicja 6.4

Powiemy, że algorytm Alg ma czasową złożoność asymptotyczną

Oczywiście najbardziej pożądane są algorytmy o złożoności liniowej. Nie zawsze jednak jest to możliwe. Złożoność większości przedstawionych w tym wykładzie algorytmów jest wielomianowa. Spotkamy się jednak również z algorytmami o złożoności wykładniczej. Takim algorytmem jest np. algorytm generowania wszystkich permutacji danego ciągu, lub metoda zerojedynkowa badania spełnialności formuł rachunku zdań. Aby zrozumieć jak istotna jest dla nas  różnica  między złożonością wielomianową a wykładniczą, rozważmy następujące zadanie.

Niech będą dane algorytmy: Alg1 o złożoności T(Alg1, n) = n2  i  Alg2 o złożoności T(Alg2, n) = 2n, rozwiązujące ten sam problem. Załóżmy, że wykonują one zadanie  o rozmiarze  k w czasie t na pewnym komputerze K. Zastanówmy się najpierw w jakim czasie zostanie wykonane przy pomocy tych algorytmów zadanie 5 razy większe. Dla algorytmu Alg1 mamy  t ´ (5k)2/ k2 = 25t, a dla algorytmu Alg2,  t ´ (25k)/2k =  t ´ (2k)4 = t5, czyli algorytm Alg1 wykona większe zadanie w czasie 25 razy dłuższym, a algorytm Alg2 potrzebuje aż t5 czasu.  Może się wydawać, że sytuacja zmieni się, jeśli algorytmy będą wykonywane na szybszym, np. 16 razy szybszym, komputerze. Jaki jest maksymalny wymiar zadania, które można rozwiązać na tym komputerze w czasie  t. Zadanie o rozmiarze k wykonamy więc 16 razy szybciej, czyli w czasie  t/16. Algorytm Alg1 może zatem wykonać w czasie t na szybszym  komputerze zadanie o rozmiarze x, gdzie

(t/16) ´ x2 =  t ´ k2 = 16k2,
czyli ostatecznie x = 4k. Algorytm Alg2 natomiast, wykona w czasie t zadanie o rozmiarze  y,  gdzie
(t/16) ´ 2y =  t ´ 2k.
Wynika stąd, że y= k+4. Alg2 wykona więc zadanie jedynie o 4 jednostki większe.
 

Pytanie 7: Która z funkcji lg (n2), czy 2lg(lgn)  ma asymptotycznie większy rząd?


« poprzedni punkt   następny punkt »