ZŁOŻONOŚĆ OBLICZENIOWA ALGORYTMÓW
pesymistyczna czasowa średnia Złożoność pamięciowa
DANE Wyznacz największą spośród 3 liczb rzeczywistych. D = { ( x, y, z ) : x,y,z R } = R R R = R3 Oblicz 2n , dla pewnej liczby naturalnej n. D = { n : n N } = N Sprawdź czy dana liczba naturalna n jest liczbą pierwszą. D = { n : n N } = N Wyznacz największy wspólny dzielnik dwóch liczb naturalnych. D = { (a,b) : a,b N } = N N = N2
Oblicz sumę płac pracowników w firmie. D = { ( n, p1, ... ,pn ) : n N , p1, ... ,pn R } Wyznacz maksimum z ciągu liczb rzeczywistych. D = { ( n, x1, ... , xn ) : n N , x1, ... , xn R } Oblicz iloczyn dwóch wektorów x, y o współrzędnych rzeczywistych. D = {( n, x1, ... , xn, y1, ... ,yn ) : n N , x1, ... , xn , y1, ... ,yn R }
Zbiór operacji jednostkowych Pascala (J) : operatory arytmetyczne : + - * / div mod operatory logiczne : and or not operatory relacyjne : < <= > >= = <> nadanie wartości zmiennej typu prostego obliczenie wartości zmiennej indeksowanej inicjalizacja wywołania procedury lub funkcji przekazanie wartości parametru aktualnego wykonanie instrukcji pustej, wejścia lub wyjścia
PEŁNA FUNKCJA ZŁOŻONOŚCI CZASOWEJ Dany jest program P w Pascalu o zbiorze danych D. Zakładamy, że : P jest poprawny obliczenie programu P na każdej danej z D jest skończone Definiujemy funkcję t : D N następująco : t(d) = ilość operacji ze zbioru J występujących w obliczeniu programu P na danej d D t - pełna funkcja złożoności czasowej programu P pełna funkcja kosztu programu P
PRZYKŁADY Wyznacz maksimum z dwóch liczb rzeczywistych x, y. D = { ( x,y ) : x,y real } program max2; t(d) var x,y : real; Max : real; begin read (x,y); 2 if x > y then Max := x 2 lub 1 else Max := y 0 lub 1 writeln (Max) 1 end. t(d) = 5
Wyznacz pierwiastki rzeczywiste równania kwadratowego ax2 + bx + c = 0 . D = { (a, b, c) : a,b,c real } = real 3
if delta = 0 then 1 t(d) = 25 lub t(d) = 16 lub t(d) = 12 program pierwiastki; t(d) var a,b,c,delta, x1,x2 : real; begin read (a,b,c); 3 delta := b*b - 4*a*c; 5 if delta > 0 then 1 delta := sqrt(delta); 2 x1 := (-b + delta) / (2*a); 5 x2 := (-b - delta) / (2*a); 5 write (x1, x2) 2 end; if delta = 0 then 1 x1 := -b/(2*a); 4 write (x1); 1 if delta < 0 then write(‘Nie ma pierwiastków rzecz') 1 lub 2 end. t(d) = 25 lub t(d) = 16 lub t(d) = 12
Oblicz n! dla n>= 0. D = { n : n byte } program silnia; t(d) var n : Byte ; silnia : LongInt ; begin readln (n); 1 if ( n = 0) or (n = 1) 3 then silnia := 1 1 else begin silnia := 1; 1 for i := 2 to n do 1 * (n-1) silnia := silnia * i ; 2 * (n-1) end; writeln (n); 1 end. t(n) = 1+3+1=5 dla n=0 lub n=1 t(n) = 1+3+1+(n-1)+2*(n-1)+1 = 3n + 3 dla n>1
Sprawdź czy liczba naturalna n, n >= 0, jest liczbą pierwszą . D = { n : n word } program pierwsza; t(d) var n, p : word; b : boolean; begin readln (n); 1 p := 2; 1 b := true; 1 while ( (p*p <= n) and b) do 3*n if n mod p = 0 then b := false; 2*(n -1)+1 p := p + 1; 2*(n -1) end; if b then writeln (‘To jest liczba pierwsza’) 1 else writeln (‘ To nie jest liczba pierwsza’); 1 end. t(n) 7n + 1
n jest liczbą parzystą , tzn .: n mod 2 = 0 t(n) = 15 n jest postaci 3*k dla pewnego k N t(n) = 22 n jest liczbą pierwszą t(n) = 7n
ROZMIAR DANYCH Dowolną funkcje r : D W nazywamy rozmiarem danych . Oblicz sumę płac pracowników w firmie. D = { ( n, p1, ... ,pn ) : n N , p1, ... ,pn R } W = { n : n N } = N Wyznacz maksimum z ciągu liczb rzeczywistych. D = { ( n, x1, ... , xn ) : n N , x1, ... , xn R } W = { n : n N } = N Oblicz iloczyn dwóch macierzy An,k , Bk,m, o wyrazach rzeczywistych D = {( n, k, m, A, B ) : n,k,m N , A Macn,k(R), B Mack,m(R) } W = {(n, k, m) : n,k,m N} = N3 lub W = { n : n = max {n,k,m} } = N
PESYMISTYCZNA ZŁOŻONOŚĆ CZASOWA J - zbiór operacji jednostkowych Pascala (niekoniecznie wszystkich) P - program w Pascalu D - zbiór danych programu P W - zbiór rozmiarów danych programu P t - pełna funkcja złożoności czasowej programu P Funkcję T: W - - N zdefiniowaną następująco : T(w) = sup { t(d) : d D ^ r(d) = w } nazywamy pesymistyczną złożonością czasową programu
Oznaczenie : f(n) = O(g(n)) NOTACJA "O" Niech g : N R . O(g) = { f : N R : istnieją stałe : c R, c > 0 i n0 N takie, że |f(n)| c * |g(n)| dla wszystkich naturalnych n n0 } Dane są dwie funkcje f, g : N R . Mówimy, że „ funkcja f jest co najwyżej rzędu funkcji g „ jeśli f O(g) . Oznaczenie : f(n) = O(g(n))
Oznaczenie : f(n) = W (g(n)) NOTACJA " W " Niech g : N R . W (g) = { f : N R : istnieją stałe : c R, c > 0 i n0 N , n > 0 takie, że |f(n)| c * |g(n)| dla wszystkich naturalnych n n0 } Dane są dwie funkcje f, g : N R . Mówimy, że „ funkcja f jest co najmniej rzędu funkcji g „ jeśli f W (g) . Oznaczenie : f(n) = W (g(n))
Oznaczenie : f(n) = Q (g(n)) NOTACJA " Q " Niech g : N R Q(g) = O(g) Ç W (g) Dane są dwie funkcje f, g : N R . Mówimy, że „ funkcja f jest dokładnie rzędu funkcji g „ jeśli f Q (g) . Oznaczenie : f(n) = Q (g(n))
WŁASNOŚCI NOTACJI "O" " ( k > 0) kf = O( f ) nr = O( ns) jeśli 0 r s Jeśli f = O(g), to f + g = O(g) Jeśli f jest wielomianem stopnia d, to f = O(nd)
Jeśli f = O(g) i g = O(h) , to f =O(h) Jeśli f = O(g) i h =O(r) , to fh = O( gr ) " (b > 1 and k ³ 0) nk = O( bn ) Przykład : n20 = O( 1.05n) "(b > 1 and k > 0) logbn = O( nk) Przykład: log2n = O( n0.5)
"( b, d > 1) logbn =O(logdn) S kr = Q ( nr+1 ) k=1
PODSUMOWANIE Dla algorytmu A i zbioru operacji J : znajdujemy funkcję g : W R , gdzie W jest zbiorem rozmiaru danych i rzeczywistą stałą c > 0 taką, że TA,J,W (w) c * |g(w)| dla prawie wszystkich w W, Wtedy piszemy T(w) = O(g(w)) ( „T jest co najwyżej rzędu g” ) lub T = O(g)
D = { ( n, p1, ... ,pn ) : n byte , p1, ... ,pn real W = { n : n byte} program suma; const ile = 100; var p : array [1..ile] of real; n : byte; s : real; begin read (n); 1 s := 0; 1 for i := 1 to n do n read (p[i]); 2n s := s + p[i]; 3n end; writeln (s) 1 end. 6n + 3 <= 7n dla n >2 T(n) = O(n)
Sprawdź czy liczba naturalna n, n >= 0, jest liczbą pierwszą . D = { n : n word } program pierwsza; t(d) var n, p : word; b : boolean; begin readln (n); 1 p := 2; 1 b := true; 1 while ( (p*p <= n) and b) do 3*n if n mod p = 0 then b := false; 2*(n -1)+1 p := p + 1; 2*(n -1) end; if b then writeln (‘To jest liczba pierwsza’) 1 else writeln (‘ To nie jest liczba pierwsza’); 1 end. t(n) 7n + 1 T(n) = O(n )
NA KONIEC Po co złożoność : Dobry algorytm jest jak „ostry nóż” - robi dokładnie to, co ma robić, z najmniejszym wysiłkiem. Używanie złego algorytmu to jak „krajanie steku korkociągiem”. Rezultat może nie być ani efektywny ani „apetyczny”.
ZADANIE. Posortuj tablicę zawierającą milion liczb (106) .
Superkomputer : wykonuje 100 milionów (108) operacji na sekundę. Sortujemy algorytmem przez wstawianie : T(n) = 2n2 T(106) = 2 * (106)2 / 108 = 20 000 sekund 5.56 godzin Komputer osobisty : wykonuje 1 milion (106) operacji na sekundę Sortujemy algorytmem przez scalanie : T(n) = 50nlgn T(106) = 50 * 106 * lg106 / 106 1000 sekund 16.67 minut Komputer osobisty wykonał zadanie 20 razy szybciej. UWAGA : Sortowanie przez wstawianie jest szybsze od sortowania przez scalanie dla małych n