ALGORYTMY I STRUKTURY DANYCH
WYKŁAD 02 Algorytmy wyszukiwania Grażyna Mirkowska
PJWSTK, ITN semestr letni 2002
Plan wykładu
Wyszukiwanie w ciągu nieuporządkowanym.
Wyszukiwanie w ciągu uporządkowanym.
– Metoda poszukiwań sekwencyjnych – Metoda poszukiwań „skokowych”.
• Optymalna długość skoku – Metoda poszukiwań binarnych.
• Analiza poprawności i kosztu
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, wynik=false
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 );
}
Koszt algorytmu
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)Prawdopodobi eń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
?
Wyszukiwanie w ciągu uporządkowanym
Problem Dany jest ciąg rosnący e[1],..,e[n] oraz element x pewnej przestrzeni liniowo uporządkowanej <E, >. Chcemy ustalić
przedział e[i], e[i+1], w którym ewentualnie mieści się x.
Specyfikacja
Specyfikacja
: wp= {(i<n) e[i]<e[i+1] , n>0 }wk= {wynik= i wttw x należy do itego przedziału}
Metoda sekwencyjna
1. Zbadamy przypadki skrajne: przedział 0 i przedział n-ty i ew. kończymy . 2. Następnie porównujemy x z kolejnymi elementami ciągu poczynając od e[2].
Jeśli x jest mniejsze prawego końca rozważanego i-tego przedziału, to znaczy , że x znajduje się w tym przedziale, e[i] x <e[i+1]. Jeśli tak nie jest, to trzeba zbadać następny przedział.
e[1] e[2] ... e[n-1] e[n]
Przedział 0 Przedział 1 Przedział n-1 Przedział n
e[3]
Metoda poszukiwań sekwencyjnych
{
if x<e[1] then i := 0 else
if x e[n] then i := n else i := 1;
while x e[i+1] { i := i+1;
} fi;
fi;
wynik := i;
}
e[i] x e[i+1], i n
e[i]x e[n], 1i n
e[i]x , xe[i+1], i+1 n xe[i] , i n
Koszt Koszt
algorytmu algorytmu
W skrajnych przypadkach mamy 1 lub 2 porównania W najgorszym razie 2 + (n-1) porównań.Czyli W(n) = O(n).
Koszt średni algorytmu sekwencyjnego
Rozszerzamy dany ciąg o elementy a i b, tzn. przyjmujemy e[0] = a i e[n+1] =b, gdzie [a,b] jest przedziałem, w którym mieszczą się
elementy ciągu oraz x. Załóżmy, że prawdopodobieństwo tego, że x przyjmuje jakąś wartość z przedziału [a,b] jest zawsze takie samo.
Mamy p(x [e[i],e[i+1])) = (e[i+1] – e[i])/(b-a) Koszt oczekiwany algorytmu A(n) =
)) 1 (
]) 1 [
] [ ( ...
3 ]) 1 [ ] 2 [ (
2 ]) [ ] 1 [
( 1 ]) 0 [ ] 1 [ 1 (
) 2 ] (
[ ] 1 2 [
] [ ] 1 1 [
] 0 [ ] 1 ) [
( 1
1
n n
e n
e e
e
n e n
e e
e a b
a i b
i e i
e a
b
n e n
e a
b e n e
A n
i
) 1 (
] 2 [ ]
[ ]
1 [
] [ ) 1 (
] [ ]
1 [ 2 1 2
1
1
2
a n b
i e n
e a
b e b a b
a b
n e n
i e e
b a a
b
n
n i
Jeśli długości przedziałów są takie same, to A(n) = n/2 +c, gdzie c<2
Skoki „co 4”
Idea Porównujemy element x z co czwartym elementem danego ciągu tak długo aż znajdziemy element większy od x. Wtedy szukamy x
sekwencyjnie wśród czterech poprzedzających go elementach ciągu.
Metoda dokładniej:
1 krok: Zbadać czy x [e[1],e[n]). Jeśli nie, to ustalić wynik zgodnie ze specyfikacją, a jeśli tak to wykonać krok 2.
2 krok: Porównywać x z kolejnymi elementami o indeksach 4i, tak długo aż (a) znajdziemy element e[4i]>x lub (b) aż przekroczymy n (a) szukamy wyniku sekwencyjnie w przedziale [e[4i- 4], e[4i]), (b) szukamy wyniku sekwencyjnie w przedziale [e[4i- 4], e[n]).
Algorytm skoki „co 4”
{ if x < e[1] then i :=0 else if x e[n] then i := n else i := 4; bool := false;
while (i n and not bool) do if x e[i] then
i := i + 4 else
bool := true fi
od;
i := i- 4;
while x e[i+1] do i := i+1 od;
fi; fi; wynik := i
e[1] x e[n]
e[j] x dla j=1,2,...,i-4, bool e[j] x dla j=1,2,...,i, bool, in e[j] x dla j=1,2,...,i-4, bool , in+4
e[j] x dla j=1,2,...,i-4, x<e[i], bool bool oraz e[i- 4] x<e[i] lub bool oraz e[i- 4] x<e[n]
Koszt
pesymistyczny:
W(n)= 2 +[n/4]+3
Skoki „co k”
{ if x < e[1] then i :=0 else if x e[n] then i := n else i := k; bool := false;
while (i n and not bool) do if x e[i] then
i := i + k else
bool := true fi
od;
i := i-k;
while x e[i+1] do i := i+1 od;
fi; fi; wynik := i }
e[j] x<e[n] dla j=1,2,...,i-k, i n+k
Optymalne k
Dla jakich wartości k algorytm ma najmniejszy koszt pesymistyczny?
Koszt pesymistyczny wyraża się funkcją f(n) = 2 + n/k + ( k-1)
Szukamy minimum tej funkcji:
f’(k) = -n/k2 + 1 f’(k) = 0 dla k = n oraz f’’ ( n)>0
Koszt pesymistyczny będzie najmniejszy, gdy k = n
Algorytm bisekcji
Metoda „dziel i zwyciężaj”
Podziel dany ciąg na dwie części. Sprawdź, w której połowie ciągu znajduje się poszukiwany element i dalej szukaj tą samą metodą w tej właśnie połowie.
{ i :=1; j := n;
while j-i >1 do m := (i+j) div 2;
if e[m] x then i := m else j := m
fi od;
wynik := j }
wp : e[1] x < e[n], n>1
wk : e[wynik] x< e[wynik+1]
Niezmiennik e[i] x e[j], i j
1+i = j oraz e[i] x e[j]
Koszt algorytmu bisekcji
Czy ten algorytm zatrzymuje się ? Czy ten algorytm zatrzymuje się ?
Niech k będzie liczbą wykonanych iteracji pętli oraz odl(k) = j - i.
Przed wykonaniem pętli mamy k=0 i odl(k) = n-1.
odl(k+1) = odl(k)/2, jeśli odl(k) jest liczbą parzystą (odl(k)-1)/2 odl(k+1) (odl(k)+1)/2 ,
jeśli odl(k) jest liczbą nieparzystą
Odl(k) jest liczbą całkowitą z przedziału [1,n-1 ] i ze wzrostem k maleje!
Istnieje zatem takie k, że odl(k)=1. A więc algorytm zatrzymuje się.
A jaka jest największa wartość k? k =[ lg n]