n - Coders` city
Transkrypt
n - Coders` city
Podstawy Informatyki Sprawność algorytmów Sprawność algorytmów Kryteria oceny oszczędności • Miara złożoności rozmiaru pamięci (złożoność pamięciowa): Liczba zmiennych + liczba i rozmiar struktur danych w algorytmie • Miara czasu wykonania (złożoność czasowa) Liczba elementarnych akcji wykonanych przez procesor w trakcie wykonania algorytmu Ulepszenia wprowadzone post factum • modyfikacja programu przez przeniesienie instrukcji ze środka na zewnątrz pętli Przykład 1 max = maksimum(t); //zwraca największą wartość w tablicy t for(i=0; i<100; i++) t[i] = t[i]*100/max; po ulepszeniu: max = maksimum(t); //zwraca największą wartość w tablicy t wspol = 100/max; for(i=0; i<100; i++) t[i] = t[i]*wspol; Ulepszenia post factum Przykład 2 Przed: Wyszukanie w liście liniowej L elementu o wartości x. Prosty algorytm zawiera warunek postaci: 1. „czy znaleziono w L wartość x” i 2. „czy został osiągnięty koniec listy L?” Po ulepszeniu: Na koniec listy dodawany jest element o wartości x. Wyszukiwanie sprowadza się tylko do sprawdzania warunku 1. Ulepszenia rzędu wielkości Problem wyszukiwania elementu w posortowanej liście L o długości N. Algorytm A: y = pierwszy_element_listy(L); while((y rozne od x) i (nie osiągnięto końca listy L)){ y = weź_następny_element_listy(L); } Algorytm A, w najgorszym przypadku wykona się w czasie rzędu N. Algorytm wykonuje się w czasie O(N) – notacja duże-O, tzn., że ∃ stała liczba K taka, że algorytm wykona się w czasie nie dłuższym niż K*N w najgorszym przypadku. Czas wykonania algorytmu rośnie liniowo z N. Notacja duże-O jest pesymistycznym oszacowaniem czasy wykonania algorytmu. Ulepszenia rzędu wielkości Wyszukiwanie binarne dla problemu wyszukiwania elementu w posortowanej liście L o długości N. start Weź całą listę L nie Czy x = L[długość_listy/2]? tak Wypisz znaleziono x Weź pierwszą lub drugą połowę listy, w zależności od wyniku porównania nie Czy rozważana lista jest pusta? tak Wypisz w liście L nie ma elementu o wartości x stop Policzenie porównań. Każde porównanie skraca długość listy wejściowej o połowę. Proces ten kończy się, gdy lista jest pusta lub gdy znaleziony zostanie poszukiwany element. Pesymistyczna liczba porównań = ile razy wielkość N można podzielić przez 2, zanim osiągnie 0, czyli log2N, a w rzeczywistości redukuje się N do 1, więc 1+log2N. Ulepszenia rzędu wielkości – wyszukiwanie binarne Porównanie liczby porównań dla wyszukiwania elementu w posortowanej liście o długości L dla dwóch algorytmów: prostego wyszukiwania binarnego N 1+ log2N 10 4 100 7 1000 10 milion 20 miliard 30 miliard miliardów 60 Czy wystarczy policzyć porównania? W algorytmie wyszukiwania binarnego wszystkie operacje oprócz porównań nie przekraczają pewnej stałej ⇒ całkowita liczba instrukcji wykonywanych przez algorytm dla listy o długości N nie przekracza: K + (K2*log2N) ⇒ złożoność pesymistyczna jest równa O(log2N). Rzędy wielkości funkcji Rzędy wielkości funkcji Rząd wielkości funkcji • opisuje czas działania algorytmu • charakteryzuje efektywność algorytmu • za jego pomocą można porównać różne algorytmy Asymptotyczna złożoność algorytmu – określenie rzędu wielkości czasu działania algorytmu, tzn. określenie szybkości wzrostu czasu działania algorytmu, gdy rozmiar danych dąży do nieskończoności. Notacja asymptotyczna W notacji asymptotycznej czas działania algorytmów opisywany jest przez funkcje określone na zbiorze liczb naturalnych ℵ. Argument funkcji jest najczęściej rozmiarem danych wejściowych. Notacja asymptotyczna Notacja Θ Dla danej funkcji g(n) oznaczamy przez Θ(g(n)) zbiór funkcji: Θ(g(n)) = {f(n): ∃ stałe c1, c2 > 0 i n0 ∈ ℵ+: c1g(n) ≤ f(n) ≤ c2g(n) ∀ n≥ n0 } Notacja Θ jest asymptotycznie dokładnym oszacowaniem; ogranicza funkcję od góry i od dołu. Przykład Dana jest funkcja kwadratowa f(n) = an2 + bn + c, gdzie a, b, c są stałymi i a > 0. Odrzucając składniki niższego rzędu otrzymujemy f(n) = Θ(n2). Wynika to z faktu, że: c1 = a/4; c2 = 7a/4 n0 = 2 * max(|b|/a, sqrt(|c|/a)) Notacja O Dla danej funkcji g(n) oznaczamy przez O(g(n)) zbiór funkcji: O(g(n)) = {f(n): ∃ stałe c > 0 i n0 ∈ ℵ+: 0 ≤ f(n) ≤ cg(n) ∀ n≥ n0 } Notacja O jest asymptotyczną granicą górną; szacuje pesymistyczny czas działania algorytmu. Θ(g(n)) ⊆ O(g(n)) Notacja asymptotyczna Notacja Ω Dla danej funkcji g(n) oznaczamy przez Ω(g(n)) zbiór funkcji: Ω(g(n)) = {f(n): ∃ stałe c > 0 i n0 ∈ ℵ+: 0 ≤ cg(n) ≤ f(n) ∀ n≥ n0 } Notacja Ω jest asymptotyczną granicę dolną; oszacowuje czas działania algorytmu dla najlepszego przypadku Twierdzenie Dla każdych dwóch funkcji f(n) i g(n) zachodzi zależność f(n) = Θ(g(n)) ⇔ f(n) = O(g(n)) i f(n) = Ω(g(n)) c1g(n) c g(n) f(n) f(n) f(n) c g(n) c2g(n) n0 n n0 n n0 n Notacja asymptotyczna Własności funkcji Założenie: funkcje f(n) i g(n) są asymptotycznie dodatnie Przechodniość f(n) = Θ(g(n)) ∧ g(n) = Θ(h(n)) f(n) = O(g(n)) ∧ g(n) = O(h(n)) f(n) = Ω(g(n)) ∧ g(n) = Ω(h(n)) Zwrotność f(n) = Θ(f(n)) f(n) = O(f(n)) f(n) = Ω(f(n)) Symetria f(n) = Θ(g(n)) ⇔ g(n) = Θ(f(n)) Symetria transpozycyjna f(n) = O(g(n)) ⇔ g(n) = Ω(f(n)) ⇒ ⇒ ⇒ f(n) = Θ(h(n)) f(n) = O(h(n)) f(n) = Ω(h(n)) Analiza kosztu czasowego Analiza kosztu czasowego zagnieżdżonych pętli Przykład for i=1 to N–1 do{ x ← pierwszy element; Algorytm sortowania bąbelkowego pętla zewnętrzna (1) wykona się N-1 razy pętla wewnętrzna (2) wykona się też N-1 razy ⇒ koszt czasowy algorytmu: T(N) = (N-1)*(N-1) = N2 – 2N – 1 ⇒ O(N2) Analiza kosztu czasowego rekurencji Przykład Poszukiwanie najmniejszego i największego elementu w nieuporządkowanej liście L Niech T(N) – pesymistyczna liczba porównań funkcji Znajdź_min_max dla listy o długości N. Wtedy: 1. Jeśli N=1, to T(1)=0 2. Jeśli N=2, to T(2)=2 2. Jeśli N>2, to T(N)=2*T(N/2)+2 ⇒ koszt czasowy algorytmu O(N) //(1) for j=2 to N do{ //(2) if (x > element o numerze j) zamień te elementy miejscami; x ← element o numerze j; } } struktura minmax{ element_listy min, max; }; minmax Znajdź_min_max(lista L){ minmax wynik,wynik1,wynik2; if(dlugosc_listy(L)==1){ wynik.min ← wynik.max ← L[1]; return wynik; } podziel_liste(L,L1,L2); //podziel listę L //na połowy L1 o L2 wynik1 ← Znajdź_min_max(L1); wynik2 ← Znajdź_min_max(L2); wynik.min ← minimum(wynik1.min, wynik2.min); wynik.max ← maximum(wynik1.max, wynik2.max); return wynik; } Dolne i górne ograniczenia Dolne i górne ograniczenia Znalezienie algorytmu rozwiązania danego problemu ustanawia górne ograniczenie dla tego zadania algorytmicznego. algorytm dla P o złożoności O(N3) .................................. algorytm dla P o złożoności O(N2) problem algorytmiczny P górne ograniczenia P Jeżeli dolne i górne ograniczenie są sobie równe z dokładnością do stałych, to problem w sensie notacji O(⋅ ) jest zamknięty. złożoność obliczeniowa P? dowód, że koszt P jest równy O(N) dolne ograniczenia P dowód, że koszt P jest równy O(N*logN) Przykład problemu, który nie jest zamknięty. Problem minimalnego drzewa rozpinającego. Udowodniono, że zadanie to wymaga O(N) czasu, gdzie N jest liczbą krawędzi w grafie, ale nie ma algorytmu, który realizowałby to zadanie w czasie liniowym.