ALGORYTMY I STRUKTURY DANYCH
WYKŁAD 02 Wyszukiwanie Grażyna Mirkowska
PJWSTK, 2003/2004
Plan wykładu
Wyszukiwanie dowolnego elementu
• Algorytm naiwny
• Analiza kosztu średniego
Wyszukiwanie minimum i maksimum
• Algorytm naiwny
• Analiza kosztu średniego
• Algorytm rekurencyjny
Wyszukiwanie w ciągu nieuporządkowanym
Problem Niech E będzie daną przestrzenią, a X jej skończonym podzbiorem. Zbadać, czy dany element x przestrzeni E należy do wybranego podzbioru X.
Metoda rozwiązania polega na porównywaniu kolejnych elementów ciągu, poczynając od
pierwszego, z elementem x. Jeśli badany element jest równy x, to kończymy postępowanie; jeśli nie, to rozważamy następny element ciągu.
Specyfikacja
Specyfikacja wp ={(ei ) ciąg n elementów przestrzeni E , n 1}
wk ={ wynik ( i n) ei = x}
Zakładamy, że elementy ciągu są przechowywane w pewnej tablicy e[1], e[2],...,e[n].
Diagram przepływu
początek
koniec i n and not wynik
x= e[i]
wynik := true
wynik := false; i := 1;
i := i+1;
x {e[1],...,e[i-1]}, wynik=false , i=1
x {e[1],...,e[i-1]}, in+1,wynik=false, in
x=e[i], in wynik=true
x {e[1],...,e[i-1]}, in, x e[i]
x {e[1],...,e[i-1]}, in+1,
Tak Nie
Algorytm Wersja 1
Wersja 1
{
i :=1; wynik := false;
while ( i n and not wynik)
{ if x=e[i] then
wynik := true else
i := i+1 fi;
} }
wynik= true, i n , e[i]=x lub
wynik=false, i=n+1, x {e[1],...,e[i-1]}
wynik = true wttw dla pewnego i n , e[i]=x
Wersja 2 Wersja 2
{
e[n+1]:= x; i:=1;
while (e[i] x ) { i := i+1; }
wynik := (i n );
}
Analiza kosztu
Operacja dominująca = porównywanie elementów W najlepszym razie algorytm wykona 1 porównanie.
W najgorszym razie n- porównań.
Koszt
Koszt
średni średni A(n)= d Dn p(d) * t(d)Prawdopodo- bieństwo wystąpienia danych d
Koszt realizacji algorytmu dla danych d
Niech p(xX)= p i załóżmy, że jest jednakowo prawdopodobne, że x znajduje się na 1szym, 2gim czy i-tym miejscu.
Wtedy p(x=e[i]) = p/n.
Zatem A(n) =1* p/n+ 2*p/n +...+n*p/n +n*(1-p) = n - (n-1)*p/2.
A koszt
pamięciowy
?
Minimum i maksimum
Dany jest ciąg elementów e[i] i = 1,...,n należących do pewnego zbioru E liniowo uporządkowanego przez relację . Znaleźć największy i najmniejszy element tego ciągu.
Wp = { e[i] e[j] dla i j}
Wk = { e[min] e[i] oraz e[max] e[i] dla wszystkich i =1,2...n}.
Znajdź minimum metodą
sekwencyjnego przeglądania ciągu.
Znajdź maksimum, tą samą metodą. T(A,n)= 2n-2
Modyfikacja algorytmu naiwnego
Algorytm naiwny nie jest
optymalny!
Jeśli e[i] jest większe od e[max], to nie ma potrzeby porównywać e[i] z e[min].
( 1j<i)(e[max] e[j] e[min]e[j]) { min :=1; max :=1;
for i := 2 to n do
if e[i] >e[max] then max := i
else
if e[i]< e[min] then min := i
fi fi od;
}
Koszt
pesymistyczny:
W(n) = 2n-2
Analiza kosztu średniego
Uwaga 1 Pierwsze porównanie jest wykonywane w każdym przebiegu pętli.
Uwaga 2 Drugie porównanie jest wykonywane tylko wtedy, gdy odpowiedź w pierwszym porównaniu jest negatywna.
Dn - zbiór wszystkich danych rozmiaru n.
A(n) = d Dn p(d)* t(d)
Zbiór wszystkich permutacji
Założymy, że wszystkie permutacje są jednakowo prawdopodobne.
p(d) = 1/n!
Koszt średni c.d.
Niech d = a1...an będzie daną permutacją liczb 1...n i b = b1,...bn będzie ciągiem takim, że
bi = liczba elementów większych niż ai na lewo od ai , tzn.
o mniejszych indeksach w ciągu d.
Przykład Niech d = 6752314, wtedy b = 0023353.
Obserwacja (a) Ciąg b jest jednoznacznie wyznaczony przez d.
(b) 0 bi < i
Drugiego porównania w algorytmie nie wykonujemy tylko
wtedy, gdy na lewo od i-tego elementu nie było liczby większej, czyli tylko wtedy gdy bi =0.
Koszt średni c.d
Prawdopodobieństwo tego, że bi =0 wynosi 1/i, ponieważ bi przyjmuje tylko wartości od 0 do i-1.
Stąd prawdopodobieństwo wykonania drugiego porównania wynosi 1-1/i.
Średni koszt dla danych d:
t(d) = (n-1) + i =2...n 1* p(drugie porównanie) = (n-1) + i=2...n (1-1/i) = 2n-2 - lg n +c
A(n) = d 1/n! t(d) = 2n - lg n + c
1/x dx= ln|x|
Min-max rekurencyjny -- przykład
Założenie:n = 2 k
4, 5, 1, 8, 33, 11, 44, 10, 7, 2, 13, 22, 3, 55, 9, 6
4, 5, 1, 8, 33, 11, 44, 10
min= max= 7, 2, 13, 22, 3, 55, 9, 6
min= max=
Dany ciąg:
4, 5, 1, 8
min= max=
33, 11, 44, 10 min= max=
7, 2, 13, 22 min= max=
3, 55, 9, 6 min= max=
4,5 1,8 33,11 44,10 7,2 13,22 3,55 9,6
1 8 10 44
1 44
Min-max rekurencyjny -- przykład c.d.
4, 5, 1, 8, 33, 11, 44, 10, 7, 2, 13, 22, 3, 55, 9, 6
4, 5, 1, 8, 33, 11, 44, 10
min= max= 7, 2, 13, 22, 3, 55, 9, 6
min=2 max=55
Dany ciąg:
4, 5, 1, 8
min= max=
33, 11, 44, 10 min= max=
7, 2, 13, 22
min=2 max=22
3, 55, 9, 6
min=3 max=55
4,5 1,8 33,11 44,10 7,2 13,22 3,55 9,6
1 8 10 44
1 44
min = 1 max = 55
Algorytm min-max rekurencyjny
obiekt function min_max (int i, j);
//deklaracja i tworzenie obietktów result, lewy, prawy;
{ if ( i+1=j ) then if e[j] > e[i] then
result.max := j; result.min := i else
result.min := j; result.max :=i fi
else
x:= (i+j-1) div 2;
lewy := min_max( i, x);
prawy := min_max( x+1, j);
if e[prawy.min]<e[lewy.min] then
result.min := prawy.min else result.min := lewy.min fi;
if e[lewy.max]< e[prawy.max] then
result.max := prawy.max else result.max := lewy.max fi;
min max
i
x
j
Poprawność min-max
wp = {( m) n = 2 m, e[i] <E, > dla i=1,...n}
wk = {(i n) e[min] e[i] , (i n) e[i] e[max]}
Jeżeli spełniony jest warunek początkowy wp , to po wykonaniu następujących
instrukcji
{wynik := min_max(1,n);
min := wynik.min;
max := wynik.max;}
spełniony będzie warunek końcowy wk.
Czy algorytm min-max zatrzymuje się?
W każdym wywołaniu funkcji min_max(i,j) parametry aktualne i, j spełniają warunek j-i+1 = 2 k dla pewnego k, 1 k m
Dla pierwszego wywołania własność jest oczywiście spełniona.
j = n, i =1
Jeżeli w ciągu są tylko 2 elementy, tzn. k=1. Wtedy nie wywołujemy powtórnie funkcji min-max4.
bo i+1=j
Jeżeli k>1 oraz j-i+1 = 2 k , to funkcja zostanie wywołana dla nowych argumentów: i, x oraz x+1, j, ale wtedy
x-i+1 = (i+j-1)/2 – i +1 = (j-i+1)/2 = 2 k-1
j-(x+1)+1 = j – ((i+j-1)/2 +1) +1 =(j-i+1)/2 = 2 k-1 max4Min-
c.d. ‘stop’ dla min-max
Długość rozważanego przez funkcję min-max ciągu maleje w kolejnych wywołaniach.
jest 2 razy mniejsza
W konsekwencji proces musi się zakończyć dla k=1.
Jeśli spełniony jest warunek początkowy wp, to algorytm min_max zatrzymuje się dla
dowolnych danych.
Poprawność algorytmu min-max
Dowód przez indukcję ze względu na liczbę wywołań rekurencyjnych funkcji min_max.
Dla jednego tylko wywołania , tzn. gdy m=1 wynik algorytmu jest poprawny.
Załóżmy, że wynik algorytmu jest poprawny dla wewnętrznych wywołań, czyli
e[k] e[lewy.max] dla i k x oraz e[k] e[prawy.max] dla x+1 k j Po wykonaniu instrukcji :
Mamy : e[k] e[result.max] dla i k j
if
e[lewy.max]<e[prawy.max]
then
result.max := prawy.max else
result.max := lewy.max fi;
Analogicznie dla
minimum
Koszt rekurencyjnego alg. min_max
Operacja dominująca - porównywanie elementów
T(min_max, 2) = 1
T(min_max, 2 k)= 2* T(min_max,2 k-1) +2
Jeśli w ciągu są tylko 2 elementy, to
wykonujemy 1 porównanie
Min- max4
Dla k>1 wykonujemy 2 wywołania
rekurencyjnie
Dwa dodatkowe porównania dla ustalenia ostatecznego
wyniku
T(min_max, n) = 3/2 n - 2
T(2k) = 3*2 k-1 - 2
Czy można zrobić lepiej?
Każdy algorytm wyznaczający minimum i maksimum dowolnego ciągu e[1],...e[n]
elementów dowolnej liniowo
uporządkowanej przestrzeni musi wykonać w przypadku pesymistycznym co najmniej [3/2 n] – 2 porównania.
min_max jest optymalnym
rozwiązaniem problemu min-max
Następne slajdy do wykorzystania na
ćwiczeniach
Algorytm min-max 3
Idea algorytmu:
Porównaj parami
elementy danego ciągu.
Mniejszy z każdej pary wstaw do ciągu M, a większy z każdej pary do ciągu W.
Dany ciąg: 4, 5, 1, 8, 34, 11, 44, 4, 7, 2,
Mniejsze: Większe:
4 1 11 4 2 5 8 34 44 7
Wybierz minimum Wybierz maksimum
4, 5, 1, 8, 34, 11, 44, 4, 7, 2,
Uwaga. Nie musimy przenosić samych elementów do tablic M i W. Wystarczy zapamiętać pozycje tych elementów.
Analiza kosztu
{ // min-max i:=1; k:=1;
while i< n do
if e[i] >e[i+1] then
w[k] :=i; m[k] :=i+1 else
w[k] :=i+1; m[k] :=i fi
i := i+2; k := k+1;
od;
min := m[1]; max :=w[1];
for i := 2 to k-1 do
if e[m[i]] < e[min] then min := m[i] fi;
if e[w[i]]> e[max] then max := w[i] fi;
od;
}
Operacja dominująca : porównywanie.
1szy krok = n/2 porównań Załóżmy, że n jest liczbą parzystą.
Wybranie minimum = n/2 - 1 porównań
Wybranie maksimum = n/2 - 1 porównań.
Razem = 3n/2 -2 porównań
Analiza poprawności
{ //rozdzielanie i:=1; k:=1;
while i< n do
if e[i] >e[i+1] then w[k] :=i; m[k] :=i+1 else
w[k] :=i+1; m[k] :=i fi
i := i+2; k := k+1;
od;
}
Dla każdego j=1...k-1 istnieje takie u<k, że e[m[j]] e[w[u]]
Dla każdego j=1...k-1 istnieje takie u<k, że e[w[j]] e[m[u]]
Żaden indeks w tablicy w[i] nie może wskazywać minimum ciągu e.
Żaden indeks w tablicy m[i] nie może wskazywać maksimum ciągu e.
Analiza poprawności c.d.
min := m[1]; max :=w[1];
for i := 2 to k-1 do
if e[m[i]] <e[min] then min := m[i] fi;
if e[w[i]]> e[max] then max := w[i] fi;
od;
Wśród indeksów m[1], ...m[k] istnieje taki indeks min, że e[min] e[i] dla wszystkich i =1,...n
Wśród indeksów m[1], ...m[k] istnieje taki indeks max, że e[i] e[max] dla wszystkich i =1,...n
e[min] e[i] dla wszystkich i =1,...n e[i] e[max] dla wszystkich i =1,...n