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.