• Nie Znaleziono Wyników

ALGORYTMY I STRUKTURY DANYCH

N/A
N/A
Protected

Academic year: 2021

Share "ALGORYTMY I STRUKTURY DANYCH"

Copied!
26
0
0

Pełen tekst

(1)

ALGORYTMY I STRUKTURY DANYCH

WYKŁAD 03 cd. Wyszukiwanie Grażyna Mirkowska

PJWSTK, 2003/2004

(2)

Plan wykładu

Drugi co do wielkości element

Algorytm turniej

K-ty co do wielkości element ciągu

Algorytm Hoare

Wyszukiwanie w ciągu uporządkowanym

Algorytm bisekcji

(3)

Problem Dany jest ciąg różnych elementów e[1],...,e[n]

pewnej przestrzeni liniowo uporządkowanej < E,  >.

Znaleźć drugi co do wielkości element tego ciągu.

WP = { e[i]  e[j] dla i  j , n>0},

WK = {1 wynik n, e[j]  e[wynik] < e[max] dla j=1,2,...,n }

e[wynik] = maximum({e[1]...,e[n]} - maximum{e[1],...,e[n]})

Algorytm naiwny : 1. Znaleźć element maksymalny. 2. Usunąć go

Drugi największy element ciągu

(4)

{

i := 2; max :=1;

while i  n do

if e[i] > e[max] then max := i fi;

i := i+1;

od;

pom := e[1]; e[1] := e[max]; e[max] := pom;

i:=3; wynik := 2;

while i n do

if e[i] > e[wynik] then wynik := i fi;

i := i+1;

od;

Swap(e[1], e[max]);

T(n) = 2n -3

Max: = 1;

for ( i =2; i<= n; i++){

if (e[i]>e[max]) {max:=i;}

}

wynik := 2;

for ( i =3; i<= n; i++){

if (e[i]>e[wynik]){wynik:=i;}

}

e[max] := maksimum(1,n);

e[wynik] := maksimum(2,n);

Algorytm naiwny

(5)

Metoda polega na porównywaniu sąsiednich elementów ciągu. Elementy większe

(wygrywające) przechodzą do następnej ‘rundy’.

2 3

4 5 7 8 1 6

4 5 8 6

5 8

Czy można to zrobić lepiej?

(6)

Każdy element, z wyjątkiem

maksymalnego przegrał co najwyżej raz.

Element drugi co do wielkości przegrał jedynie z elementem maksymalnym.

Wśród elementów,

które grały z największym!

Por. przykład

Analiza metody

(7)

Krok1. Zbudowanie drzewa turnieju.

Załóżmy, że n= 2k.

Krok 2. Wybranie elementu drugiego

największego. lg n -1

A ile elementów przegrało

z największym?

Tyle, ile było ‘rund’!

n -1

porównań

T(n)= n + lg n -2

Koszt algorytmu Turniej

(8)

Problem: Dany jest ciąg n-elementów pewnej przestrzeni liniowo uporządkowanej <E,  >.

Znaleźć k-ty największy element tego ciągu.

2, 4, 6, 12, 78, 45, 3, 33, 17, 22 Element największy = 78

element drugi co do wielkości = 45 3-ci największy = 33

4-ty największy = 22

k-ty największy element

(9)

Krok1. Wyszukaj element e[max] największy wśród elementów e[i],...,e[n];

Krok 2. Zamień elementy na pozycjach i-tej oraz max

Krok 3. Powtórz postępowanie dla następnego i.

T(n) = (n-1) + (n-2) +... +(n-k) = k*n - k*(k+1)/2

Pierwsze rozwiązanie

(10)

Zakładam, że elementy w ciągu e nie powtarzają się.

{ x := 1;

while x k do max := x;

for i := x+1 to n do

if e[i] > e[max] then max := i fi od;

swap(e[x], e[max]);

x := x+1;

od;

wynik := e[k]

}

e[1]>...>e[x-1] >{e[x],...,e[n] }

e[max] {e[x],...,e[n]}

e[1]>...>e[x-1] >{e[x],...,e[n] }

Algorytm naiwny

(11)

Rozdziel wszystkie elementy na większe od pewnego elementu M(część starsza) i na mniejsze od M (część młodsza).

M = mediana

Umieść medianę tak by oddzielała cześć młodszą od starszej.

Wynikiem jest mediana, jeśli w części starszej jest tylko k-1 elementów.

W przeciwnym przypadku: jeśli elementów starszych jest >k-1, to szukaj k-tego elementu w części starszej. Jeśli elementów starszych jest mniej niż k-1, to szukaj elementu

k-(liczba elementów starszych+1)

Czy można to zrobić taniej?

(12)

10 5 7 9 11 4 3 2 12 8 6 1

W podanym ciągu szukamy 7tego co do wielkości elementu

mediana

Część młodsza 5 7 9 4 3 2 6 1

Część starsza 11 12

10

5 7 9 4 3 2 6 1 mediana

Część młodsza 4 3 2 1

Część starsza 7 9 6

5

Szukam 4-go największego

Wynikiem jest element 5

Przykład

(13)

function Hoare(l, p, k) { j := SPLIT(l, p);

if ( p-j = k-1) then wynik := e[j]

else

if p-j>k-1 then Hoare(j+1, p, k) else

Hoare(l,j-1, k-(p-j+1)) fi

{e[1]...,e[j-1]}< e[j]<{e[j+1],...,e[n]}

K-ty największy znajduje się wśród elementów e[j+1],... e[p]

K-ty największy znajduje się wśród elementów e[l],... e[j-1]

Zakładam, że elementy w ciągu nie powtarzają się i, że algorytm zwraca jako wynik wartość k-tego największego elementu.

Algorytm Hoare

(14)

int function SPLIT(lewy,prawy){

mediana := e[lewy];

i := lewy+1; j := prawy;

bool := true;

while (bool) do

while (j>lewy andif e[j] mediana ) do j := j-1 od;

while (i<j andif e[i] < mediana) do i := i+1 od;

if (i<j) then

swap(e[i], e[j]); i := i+1; j := j-1;

else bool := false fi od;

swap(e[lewy],e[j]);

return j;

(k, lewy< k <j) e[k] < e[j]

(k, j < k  prawy) e[j]  e[k]

Algorytm rozdzielania

powrót

(15)

10, 5, 9, 8, 14, 7, 12, 3, 11

i j

mediana

14 3

10, 5, 9, 8, 3, 7, 12, 14, 11

i j

mediana

10, 5, 9, 8, 3, 7, 12, 14, 11

7 10

i < j

i > j powrót

Jak to działa?

(16)

Każdy element jest co najwyżej raz porównywany z medianą.

Koszt algorytmu SPLIT

Czyli T(SPLIT, n ) = n-1 = (n)

W( n,k) = n-1 +W( n-1,k) Czyli W(n,k)= k*n – k(k+1)/2 A(n,k) = (n-1) + 1/n[  j=1...n-k A(n-j, k) +  j=n-k+2... n A(j-1,k – (n-j+1)]

Szukanie w części starszej Szukanie w części młodszej

A(n,k) = O(n)

Koszt algorytmu Hoare

(17)

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].

e[1] e[2] ... e[n-1] e[n]

Przedział 0 Przedział 1 Przedział n-1 Przedział n

e[3]

(18)

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], 1i  n

e[i]x , xe[i+1], i+1  n xe[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).

Poniważ x e[i+1],

to i+1 nie może być równe n,bo z wcześniejszych porównań wiemy, że

x<e[n]. Czyli i+1<n

(19)

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 (

] [ ]

1 [ 2

1 2 1

b a a b e n e i n e n

Jeśli długości przedziałów są takie same, to

(20)

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 := i

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]

(21)

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ę.

(22)

Następne slajdy będą wykorzystane na

ćwiczeniach

(23)

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]),

omiń

(24)

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;

e[1]  x  e[n]

e[j]  x dla j=1,2,...,i-4,  bool e[j]  x dla j=1,2,...,i,  bool, in e[j]  x dla j=1,2,...,i-4,  bool , in+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:

(25)

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;

e[j]  x<e[n] dla j=1,2,...,i-k, i  n+k

(26)

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

Cytaty