Wykład 2 Poprawność algorytmów 1
Przegląd Ø Poprawność algorytmów Ø Podstawy matematyczne: Przyrost funkcji i notacje asymptotyczne Sumowanie szeregów Indukcja matematyczna 2
Poprawność algorytmów Ø Algorytm jest poprawny jeżeli dla każdego legalnego wejścia kończy swoje działanie i tworzy pożądany wynik. Ø Automatyczne dowiedzenie poprawności nie możliwe Ø Istnieją jednak techniki i formalizmy pozwalające na dowodzenie poprawności algorytmów 3
Poprawność praktyczna i całkowita Całkowita poprawność Zawsze ten punkt zostanie osiągnięty i otrzymamy poprawny wynik Poprawne dane algorytm Wynik Praktyczna Jeśli ten punkt został osiągnięty to otrzymaliśmy poprawny wynik Poprawne dane algorytm Wynik 4
Dowodzenie Ø W celu dowiedzenia poprawności algorytmu wiążemy ze specyficznymi miejscami algorytmu stwierdzenia (dotyczące stanu wykonania). np., A[1],, A[k] są posortowane niemalejąco Ø Warunki początkowe (Precondition) stwierdzenia, których prawdziwość zakładamy przed wykonaniem algorytmu lub podprogramu (INPUT) Ø Warunki końcowe (Postcondition) stwierdzenia, które muszą być prawdziwe po wykonaniu algorytmu lub podprogramu (OUTPUT) 5
Niezmienniki pętli Ø Niezmienniki stwierdzenia prawdziwe za każdym razem kiedy osiągany jest pewien punkt algorytmu (może to zdarzać się wielokrotnie w czasie wykonania algorytmu, np. w pętli) Ø Dla niezmienników pętli należy pokazać : Inicjalizację prawdziwość przed pierwszą iteracją Zachowanie jeśli stwierdzenie jest prawdziwe przed iteracją to pozostaje prawdziwe przed następną iteracją Zakończenie kiedy pętla kończy działanie niezmiennik daje własność przydatną do wykazania poprawności algorytmu 6
Przykład: poszukiwanie binarne (1) n n Chcemy mieć pewność, że jeżeli zwracany jest NIL to wartości q nie ma w tablicy A niezmiennik: na początku każdego wykonania pętli while A[i] < q dla każdego i [1..left-1] oraz A[i] > q dla każdego i [right+1..n] left 1 right n do j (left+right)/2 if A[j]=q then return j else if A[j]>q then right j-1 else left=j+1 while left<=right return NIL Ø inicjalizacja: left = 1, right = n niezmiennik jest prawdziwy (nie ma elementów w [1..left-1] i [right+1..n] ) 7
Przykład: poszukiwanie binarne (2) n niezmiennik: na początku każdego wykonania pętli while A[i] < q dla każdego i [1..left-1] oraz A[i] > q dla każdego i [right+1..n] left 1 right n do j (left+right)/2 if A[j]=q then return j else if A[j]>q then right j-1 else left=j+1 while left<=right return NIL Ø zachowanie: jeśli A[j]>q, to A[i] > q dla wszystkich i [j..n], ponieważ tablica jest posortowana. Wtedy przypisano j-1 do right. Stąd, druga część niezmiennika jest spełniona. Analogicznie pokazuje się pierwszą część. 8
Przykład: poszukiwanie binarne (3) n niezmiennik: na początku każdego wykonania pętli while A[i] < q dla każdego i [1..left-1] oraz A[i] > q dla każdego i [right+1..n] left 1 right n do j (left+right)/2 if A[j]=q then return j else if A[j]>q then right j-1 else left=j+1 while left<=right return NIL Ø Zakończenie: kiedy pętla kończy działanie, mamy left > right. Niezmiennik oznacza, że q jest mniejsze od wszystkich elementów A na lewo od left oraz większy od wszystkich elementów A na prawo od right. To wyczerpuje wszystkie elementy A. 9
Przykład: sortowanie przez wstawianie Ø niezmiennik: na początku każdego wykonania pętli for, A[1 j-1] składa się z posortowanych elementów for j=2 to length(a) do key A[j] i j-1 while i>0 and A[i]>key do A[i+1] A[i] i-- A[i+1] key inicjalizacja: j = 2, niezmiennik jest trywialny, A[1] jest zawsze posortowana zachowanie: wewnątrz pętli while przestawia się elementy A[j-1], A[j-2],, A[j-k] o jedną pozycję bez zmiany ich kolejności. Element A[j] jest wstawiany na k-tą pozycję, tak że A[k-1] A[k] A[k+1]. Stąd A[1..j-1] jest posortowane. zakończenie: kiedy pętla się kończy (j=n+1) niezmiennik oznacza, że cała tablica została posortowana. 10
Notacje asymptotyczne Ø Cel: uproszczenie analizy czasy wykonania, zaniedbywanie szczegółów, które mogą wynikać ze specyficznej implementacji czy sprzętu zaokrąglanie dla liczb: 1,000,001 1,000,000 zaokrąglanie dla funkcji: 3n 2 n 2 Ø Główna idea: jak zwiększa się czas wykonania algorytmu wraz ze wzrostem rozmiaru wejścia (w granicy). Algorytm asymptotycznie lepszy będzie bardziej efektywny dla prawie wszystkich rozmiarów wejść (z wyjątkiem być może małych ) 11
Notacje asymptotyczne Ø Notacja O (duże O) Asymptotyczne ograniczenie górne f(n) = O(g(n)), jeżeli istnieje stała c i n 0, takie, że f(n) c g(n) dla n n 0 f(n) i g(n) są nieujemnymi funkcjami całkowitymi Ø Korzysta się z niej przy analizie najgorszego przypadku. Czas działania c g( n) f (n) n0 Rozmiar wejścia 12
Notacje asymptotyczne Ø Notacja Ω (duża Ω) Asymptotyczne ograniczenie dolne f(n) = Ω(g(n)) jeśli istnieje stała c i n 0, takie, że c g(n) f(n) dla n n 0 Ø Opisuje najlepsze możliwe zachowanie się algorytmu Czas działania f (n) c g( n) n 0 Rozmiar wejścia 13
Notacje asymptotyczne Ø Prosta zasada: odrzucamy mniej istotne dla czasu składniki i czynniki stałe. 50 n log n jest O(n log n) 7n - 3 jest O(n) 8n 2 log n + 5n 2 + n jest O(n 2 log n) Ø O jest ograniczeniem górnym więc np. (50 n log n) jest typu O(n 5 ), ale interesuje nas najlepsze możliwe oszacowanie w tym przypadku jest to O(n log n) 14
Notacje asymptotyczne Ø Notacja Θ (duża Θ ) Dokładne oszacowanie asymptotyczne f(n) = Θ(g(n)) jeżeli istnieją stałe c 1, c 2, i n 0, takie, że c 1 g(n) f(n) c 2 g(n) dla n n 0 Ø f(n) = Θ(g(n)) wtedy i tylko wtedy, gdy f(n) = Ο(g(n)) i f(n) = Ω(g(n)) Czas działania c 2 g (n ) f (n) c g (n) 1 n 0 Rozmiar wejścia 15
Notacje asymptotyczne Ø Istnieją dwie inne notacje asymptotyczne: małe o" f(n)=o(g(n)) mocniejsze ograniczenie analogiczne do O Dla każdego c, musi istnieć n 0, takie, że f(n) c g(n) dla n n 0 mała omega" f(n)=ω(g(n)) analogicznie dla Ω 16
Notacje asymptotyczne Ø Analogie do zależności pomiędzy liczbami: f(n) = O(g(n)) f g f(n) = Ω(g(n)) f g f(n) = Θ(g(n)) f = g f(n) = o(g(n)) f < g f(n) = ω(g(n)) f > g Ø Zwykle zapisujemy: f(n) = O(g(n)), co formalnie powinno być rozumiane jako f(n) O(g(n)) 17
Szeregi Ø Szereg geometryczny Dana jest liczba całkowita n 0 i rzeczywiste 0< a 1 n i= 0 1 a = + + + + = 1 a i 2 n a 1 a a... a n+ 1 Szereg geometryczny reprezentuje przyrost wykładniczy Ø Szereg arytmetyczny n i= 0 i= 1+ 2 + 3 +... + n= Przyrost kwadratowy n(1 + n) 2 18
Sumowanie Ø Czas działania sortowania przez wstawianie jest zdeterminowany przez zagnieżdżone pętlę for j 2 to n do key A[j] wstaw A[j] do posortowanej sekwencji A[1..j-1] i j-1 while i>0 and A[i]>key do A[i+1] A[i] i-- A[i+1]:=key Ø Czas wykonania pętli reprezentuje szereg n ( 1) ( 2 j = O n ) j= 2 czas c 1 c 2 0 c 3 c 4 c 5 c 6 c 7 ile razy n n-1 n-1 n-1 n t j 2 j n ( t 1) j 2 j n= ( t 1) j 2 j = n-1 = 19
Dowody indukcyjne Ø Chcemy pokazać prawdziwość własności P dla wszystkich liczb całkowitych n n 0 Ø Założenie indukcyjne: dowodzimy prawdziwości P dla n 0 Ø Krok indukcyjny: dowodzimy, że z prawdziwości P dla wszystkich k, n 0 k n 1 wynika prawdziwość P dla n Ø Przykład: n S( n ) = i= 0 i = n( n + 1), 2 dla n 1 Ø Założenie ind. S(1) 1 = i = i= 0 1(1 + 1) 2 20
Dowody indukcyjne Ø Krok indukcyjny k kk ( + 1) Sk ( ) = i = dla for 1 k n 1 2 i= 0 n n 1 Sn ( ) = i= i+ n= Sn ( 1) + n= i= 0 i= 0 2 ( n 1+ 1) ( n n+ 2 n) = ( n 1) 2 + n= 2 = nn ( + 1) = 2 21