Pretraˇ zivanje i sortiranje

4.3 Pretraˇ zivanje i sortiranje

Pretraˇzivanje i sortiranje nizova elemenata su medu najznaˇcajnijim postup- cima u modernom raˇcunarstvu. Tim problemima posve´cene su mnoge knji-

ge. Postoji nekoliko razloga tome. Kao prvo, i pretraˇzivanje i sortiranje su problemi toliko raˇsireni u raˇcunarstvu da gotovo da i nema raˇcunalnog programa u primjeni koji u nekom svom dijelu ne sortira podatke ili ih ne pretraˇzuje. Drugo, sortiranje je problem koji je dovoljno jednostavan i jasan

da se moˇze uzeti kao model za objaˇsnjavanje metoda izrade algoritama. Nadalje, postoji ˇcitav niz detaljno razradenih algoritama sortiranja, koji se koriste razliˇcitim metodama izrade algoritama. Ovaj je problem pogodan i za objaˇsnjavanje raˇcunanja donje mede sloˇzenosti problema, jer mu se moˇze odrediti netrivijalna donja meda.

4.3.1 Pretraˇ zivanje Problem pretraˇzivanja moˇze se zadati na sljede´ci naˇcin:

Problem 4.1

ULAZ: Niz brojeva A = a 1 ,...,a n i broj x.

IZLAZ: DA ako je x ∈ A, NE ako x 6∈ A. Slijedno pretraˇ zivanje

Prvi algoritam pretraˇzivanja je ujedno i najjednostavniji oblik pretraˇzivanja neuredene liste. Algoritam redom usporeduje elemente liste sa zadanom vrijednoˇs´cu. Ako je neki od elemenata jednak traˇzenom, algoritam staje i odgovara da je naˇsao traˇzenu vrijednost. U suprotnom, algoritam prolazi kroz cijelu listu do kraja i odgovara da nije pronaˇsao zadanu vrijednost.

Algoritam 4.5

ULAZ: Zadana vrijednost x, lista a 1 ,...,a n

IZLAZ: Da ako vrijednost x postoji u listi, a ne u suprotnom.

1. i := 1.

2. ako je i > n onda odgovori ne i stani.

3. Ako je a i = x odgovori da i stani.

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE

4. i := i + 1.

5. Idi na 2. Jasno je da ´ce ovaj algoritam stati nakon najviˇse n prolaza kroz korake

od 2 do 5. Isto tako je oˇcito da ´ce algoritam vratiti da ako traˇzena vrijednost postoji u listi, dok ´ce u suprotnom vratiti ne.

Pogledajmo sada sloˇzenost ovog algoritma. U najgorem sluˇcaju, kada traˇzene vrijednosti nema u listi, ovaj algoritam ima n prolaza kroz korake od 2 do 5, a u (n + 1)-vom prolazu stane u koraku 2. Svi koraci ovog algoritma su konstantnog trajanja, odnosno za njih je potreban konstantan broj procesorskih otkucaja. Dakle, sloˇzenost ovog algoritma moˇze se opisati sljede´com formulom:

T search

max

(n) = c 1 +n ·c 2 +c 3 .

Pri tome je c 1 vrijeme trajanja prvog koraka algoritma, c 2 ukupno vri- jeme trajanja koraka 2 do 5, a c 3 vrijeme trajanja koraka 2. Dakle,

T search

(n) = Θ(n).

max

Pogledajmo kako ovaj algoritam radi kada traˇzena vrijednost postoji u listi. U tom sluˇcaju, za algoritam je najgore da vrijednost bude na posljed- njem mjestu u listi. Tada se koraci 2 i 3 izvrˇsavaju n puta, a koraci 4 i 5 n − 1 puta. U tom je sluˇcaju

T search

pri ˇcemu je c 1 trajanje prvog koraka, c 2 trajanje koraka 2 i 3 zajedno, a

c 3 trajanje koraka 4 i 5 zajedno. Najbolji je sluˇcaj kada se element nalazi na prvom mjestu u listi. Tada se koraci 1 do 3 izvrˇsavaju toˇcno jednom, a koraci 4 i 5 nijednom. Sloˇzenost je u najboljem sluˇcaju

T search

min

(n) = c 1 = Θ(1).

Pogledajmo joˇs i prosjeˇcni sluˇcaj kada se element nalazi u listi. Pret- postavljamo da je vjerojatnost da se traˇzeni element nalazi na bilo kojem mjestu u listi jednaka i iznosi 1 n , odnosno, distribucija elemenata je uni- formna. Ako se element nalazi na i-tom mjestu u listi 1 ≤ i ≤ n, onda se korak 1 izvrˇsava jednom, koraci 2 i 3 i puta, a koraci 4 i 5 i − 1 puta. Stoga imamo:

POGLAVLJE 4. ALGORITMI 141

+( + ) · n = Θ(n).

Ako je lista neuredena, bolje od ovog algoritma se ne moˇze. Ako su, medutim, elementi u listi uredeni po veliˇcini, onda se moˇze prona´ci bolji algoritam za odredivanje postojanja neke vrijednosti u listi.

Binarno pretraˇ zivanje Pretpostavimo da je zadana sortirana lista, tj. lista u kojoj su elementi

poredani od najmanjeg do najve´ceg. Pretraˇzivanje koje se u tom sluˇcaju moˇze koristiti, naziva se binarno pretraˇzivanje. Uredenost liste omogu´cuje da se ne pregledavaju svi elementi liste, ve´c samo neki od njih. Prvo usporedujemo zadanu vrijednost s ele- mentom koji se nalazi u sredini liste (ili otprilike u sredini, ako lista ima paran broj elemenata). Ako je taj element jednak traˇzenoj vrijednosti, onda zavrˇsavamo s pretraˇzivanjem. Ako nije tako, onda se gleda je li vrijednost srednjeg elementa liste ve´ca ili manja od traˇzene. Ako je vrijednost ve´ca od traˇzene, onda se traˇzeni element, ukoliko se nalazi u listi, mora nalaziti u njenoj prvoj polovici. Ako je srednji element manji od traˇzenog, onda traˇzeni element, ukoliko se nalazi u listi, mora biti u drugoj polovici liste. U drugom se koraku uzima polovica liste u kojoj se moˇze nalaziti traˇzeni element i na njoj se primjenjuje binarno pretraˇzivanje. Tako se lista smanjuje dok se ne dode do jednoˇclane liste, u kojoj se izravno provjerava sadrˇzi li njen element traˇzenu vrijednost ili ne. Formalno, algoritam izgleda ovako:

Algoritam 4.6 (Binarno pretraˇ zivanje) binsearch(f, l, x, a) ULAZ: Kursor f na poˇcetak liste, kursor l na kraj liste i traˇzena vrijednost

x, lista a 1 ,...,a n . IZLAZ: Da ako vrijednost x postoji u listi, a ne u suprotnom.

f 1. p := +l ⌊

2. Ako je a p = x vrati da i stani.

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE

3. Ako je a p > x i ako je p > f onda pozovi binsearch(f, p − 1, x, a).

4. Ako je a p < x i ako je p < l onda pozovi binsearch(p + 1, l, x, a).

5. Vrati ne i stani. Ovakvi algoritmi koji svode problem na jedan ili viˇse problema istog tipa,

ali manje dimenzije nazivaju se podijeli pa ovladaj (engl. divide and conquer) algoritmi. Podijeli pa ovladaj je vrlo efikasna metoda, koja najˇceˇs´ce daje vrlo efikasne algoritme.

Propozicija 4.8 Binarno pretraˇzivanje je korektan algoritam za pretraˇzi- vanje sortirane liste.

Dokaz. Treba dokazati da ´ce algoritam uvijek stati, te da ´ce vratiti ispravan odgovor.

Pretpostavimo da x nije u listi. Tada algoritam sigurno ne´ce stati u koraku 2. No kod svakog novog poziva funkcije binsearch, njoj se smanji parametar f ili joj se pove´ca parametar l. Tako da je nakon konaˇcno mnogo prolaza sigurno l − f ≤ 1. No, kada se to dogodi, ne´ce biti zadovoljen uvjet izvrˇsavanja ni koraka 3, ni koraka 4, pa ´ce se izvrˇsiti korak 5 i algoritam ´ce stati s ispravnim odgovorom.

Pretpostavimo da se x nalazi u listi. Primijetimo da je kod svakog poziva funkcije binsearch uvijek a f ≤x≤a l . Drugim rijeˇcima, element koji ima vrijednost x je uvijek izmedu a f ia l . No, zbog pribliˇzavanja vrijednosti f i l u svakom prolazu, na kraju ´ce postati a p = x i algoritam ´ce stati u koraku

2 i to s ispravnim odgovorom. Odredimo sada sloˇzenost ovog algoritma. Neka je n duljina liste koja se promatra. Ako je n = 1, onda ´ce se, sadrˇzi

li lista vrijednost x, izvrˇsiti samo koraci 1 i 2. Ne sadrˇzi li lista vrijednost x, izvrˇsit ´ce se korak 1, provjerit ´ce se uvjeti koraka od 2 do 4 i na kraju

´ce se izvrˇsiti korak 5. Kako su sve operacije u svim koracima elementarne, sloˇzenost je svakog koraka konstantna. Odavde zakljuˇcujemo da je

(1) = Θ(1). No, onda je i

T binsearch

T binsearch

avg

Pretpostavimo sada najgori sluˇcaj za ve´ce n-ove. Najgore je za algoritam kada se vrijednost x ne nalazi u listi. U tom sluˇcaju se izvrˇsava korak 1, provjerava se uvjet koraka 2, te se izvrˇsava korak 3 ili 4. Primijetimo da

´ce sloˇzenost biti neˇsto manja ako se izvrˇsi korak 3, jer se onda provjerava samo uvjet tog koraka, dok se u suprotnom provjerava uvjet koraka 3, ali i koraka 4. No, ovdje se radi o dodatnom konstantnom vremenu, pa to ne´ce

POGLAVLJE 4. ALGORITMI 143

utjecati na ocjenu sloˇzenosti ovog algoritma. Dakle, moˇzemo zakljuˇciti da je sloˇzenost binarnog pretraˇzivanja dana sa:

Rekurzija koju trebamo rijeˇsiti glasi:

t n =t n 2 +c 1 .

To je podijeli pa ovladaj rekurzija. Ona se rjeˇsava tako da se stavi supsti- tucija a n =t 2 n . Sada je

a n =t 2 n =t 2n 2 +c 1 =t 2 n−1 +c 1 =a n −1 +c 1 . Izvrˇsi se homogenizacija

ˇcime se dobiva homogena rekurzija

a n = 2a n −1 −a n −2 .

Karakteristiˇcna jednadˇzba posljednje rekurzije je

x 2 − 2x + 1 = 0.

Ona ima dvostruki korijen x 1,2 = 1, pa je op´ce rjeˇsenje rekurzije dano sa

n =C 1 ·1 +C 2 ·n·1 .,

odnosno,

t 2 n =C 1 +C 2 · n.

Iz posljednjega slijedi da je T binsearch

(n) = t n =C 1 +C 2 · log 2 n. Drugim rijeˇcima,

max

T binsearch

max

(n) = O(lg n).

Prosjeˇcnu ´cemo sloˇzenost izraˇcunavati samo za sluˇcaj kada se element nalazi u listi. Jasno je da, ako se element ne nalazi u listi sloˇzenost iznosi Θ(lg n).

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE Neka lista ima n elemenata. Bez smanjenja op´cenitosti moˇzemo pretpo-

staviti da je n = 2 k − 1. Ovo je vaˇzno samo zato da osiguramo da u svakom koraku niz ima srednji element.

U prvom koraku algoritma pregledavamo srednji element. Ako je traˇzeni element jednak srednjem, onda ´ce algoritam zavrˇsiti u jednom koraku. Slje- de´ca dva elementa: onaj koji se nalazi na ˇcetvrtini liste i onaj koji se nalazi na tri ˇcetvrtine liste, moˇzemo na´ci u dva koraka. Nadalje, imamo 4 elementa koja nalazimo u tri koraka, itd. Dakle, imamo sluˇcajnu varijablu

2 binsearch i X −1 T avg

Pogledajmo na trenutak neˇsto op´cenitiju sumu niza:

X k R(x) = i i −1 ·x .

i =1

Formalno integriramo ovaj red i dobivamo:

x +1 −1

R(x) =

x −1

i =1

Sada to natrag formalno deriviramo i dobivamo

R(x) = ·x − (k + 1) · x +1 . (4.2)

Uvrstimo li (4.2) u (4.2), dobit ´cemo:

k binsearch

Iz (4.3) i definicije broja k slijedi da je

POGLAVLJE 4. ALGORITMI 145

lg n T avg

binsearch

(n) = c 1 · lg(n − 1) +

. n −1

Konaˇcno,

T binsearch

avg

(n) = Θ(lg n).

I na kraju, potrebno je izraˇcunati sloˇzenost binarnog pretraˇzivanja u najboljem sluˇcaju. Najbolji je sluˇcaj kada se traˇzeni element nalazi toˇcno u sredini liste. Tada se on pronalazi u toˇcno jednom koraku, pa je

T binsearch

min

(n) = Θ(1).

4.3.2 Sortiranje Preduvjet koji lista mora zadovoljiti da bi se na njoj moglo primijeniti

binarno pretraˇzivanje jest da lista bude sortirana. To nije jedini algori- tam i jedina situacija koja zahtjeva sortiranu listu. Zapravo, sortiranje je jedna od najˇceˇs´cih operacija koje raˇcunalo izvodi. Stoga nije ˇcudno da je problemu sortiranja posve´cena posebna paˇznja u teoriji algoritama. Ovdje ´cemo opisati nekoliko razliˇcitih algoritama sortiranja i usporediti njihovu sloˇzenost.

Sortiranje izborom Prvi, vrlo jednostavan algoritam sortiranja je sortiranje izborom (engl. se-

lection sort) . Algoritam radi sljede´ce: u listi se pronalazi najmanji element i on mijenja mjesto s prvim elementom u listi. Nakon toga, prvi ´ce sadrˇzavati onu vrijednost koju ´ce sadrˇzavati u konaˇcnoj, sortiranoj listi, tj. najmanju vrijednost u listi. Sada se isti postupak ponavlja za preostale elemente, osim prvog. Drugim rijeˇcima, postupak se ponavlja za elemente od drugog do posljednjeg. U svakom sljede´cem prolazu se dio liste koji treba obraditi smanjuje za jedan element. Zbog toga, ako je lista dugaˇcka n elemenata, onda ´ce, nakon n − 1 prolaza, ovaj algoritam sortirati listu.

Primjer 4.2 Sortirajmo listu

7 3 5 1 8 4 2 9 6 Najmanji element je onaj s vrijednoˇs´cu 1.

7 3 5 1 8 4 2 9 6 Zamijenimo ga s prvim elementom

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE

U ostatku element s najmanjom vrijednoˇs´cu je onaj s vrijednoˇs´cu 2.

1 2 3 4 5 6 7 8 9 Zapiˇsimo ovaj algoritam formalno: Algoritam 4.7

ULAZ: Lista a 1 ,...,a n IZLAZ: Sortirana lista koja se sastoji od istih elemenata kao i ulazna lista.

1. Za i := 1, . . . , n − 1 radi korake 2-5.

2. min := i.

3. Za j := 2, . . . , n radi korak 4.

4. Ako je (a j <a i ) min := j.

5. swap(a i ,a min ).

POGLAVLJE 4. ALGORITMI 147 Jasno je da se koraci 1, 2 i 5 ponavljaju toˇcno n − 1 puta, bez obzira

na instancu problema. Koraci 3 i 4 se u svakom prolazu ponavljaju razliˇcit broj puta - u prvom prolazu n − 1 puta, u drugom n − 2 puta, itd. Jedina je razlika medu razliˇcitim instancama problema u tome koliko ´ce se puta izvesti pridruˇzivanje vrijednosti varijabli min u koraku 4. Najgori je sluˇcaj kada je uvjet u koraku 4 uvijek ispunjen. Treba napomenuti da se ovdje radi o hipotetiˇckom najgorem sluˇcaju te da on nije izvediv za liste ve´ce od

2 elementa, jer ne postoji takva instanca za koju bi uvjet u koraku 4 uvijek bio ispunjen. Imamo

1 ·n+c 2 ·

2 ·n+ 2 ·n , odnosno

U najboljem se sluˇcaju, pridruˇzivanje u koraku 4 ne´ce izvrˇsiti nikad. Taj sluˇcaj je realan sluˇcaj, kada je lista ve´c unaprijed sortirana. Tada je

X SelectionSort −1 T min

T SelectionSort

(n) = O(n 2 ).

min

Kako prosjeˇcna sloˇzenost mora biti izmedu najbolje i najgore, zakljuˇcujemo

Jednostavno sortiranje zamjenom Sortiranje zamjenom (engl. simple exchange sort) je joˇs jedan od osnovnih

algoritama sortiranja. Sortiranje se vrˇsi tako da se usporeduje prvi element niza sa svakim iza njega. Kada se naide na element u listi koji je manji od prvog, zamjenjuje mu se mjesto s prvim. Sada se nastavljaju usporedivati

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE preostali elementi s novim prvim elementom u listi. Nakon prvog prolaza

kroz listu, u prvom ´ce se elementu liste nalaziti najmanja vrijednost u listi. Nakon toga, postupak se ponavlja za drugi element liste i tako redom. U svakom koraku se jedna vrijednost postavlja u element liste na kojem ´ce se nalaziti i u izlaznoj, sortiranoj listi, pa ´ce se algoritam zavrˇsiti nakon (n − 1)-og koraka.

Primjer 4.3 Opet sortirajmo istu listu:

7 3 5 1 8 4 2 9 6 Najprije prvi i drugi element mijenjaju mjesta.

3 7 5 1 8 4 2 9 6 Sada se pretraˇzuje dalje i dode se do ˇcetvrtog elementa, koji mijenja

mjesto s prvim:

1 7 5 3 8 4 2 9 6 Svi daljnji elementi su manji od prvog, pa u prvom prolazu viˇse nemamo

ˇsto mijenjati.

1 7 5 3 8 4 2 9 6 Sada se usporeduju elementi s drugim elementom liste. Odmah nalazimo

da je tre´ci element manji od drugog, pa im mijenjamo mjesta:

1 5 7 3 8 4 2 9 6 Daljnji koraci su:

POGLAVLJE 4. ALGORITMI 149

1 2 3 4 5 6 7 8 9 Formalno, ovaj algoritam moˇzemo opisati na sljede´ci naˇcin: Algoritam 4.8

ULAZ: Lista a 1 ,...,a n IZLAZ: Sortirana lista koja se sastoji od istih elemenata kao i ulazna lista.

1. Za i := 1, . . . , n − 1 radi korake od 2 do 3.

2. Za j := i + 1, . . . , n radi korak 3.

3. Ako je a i >a j onda swap(a i ,a j ). Ocijenimo sloˇzenost ovog algoritma. U svakom sluˇcaju, vanjska se petlja

izvodi toˇcno n −1 puta. Unutarnja se petlja u prvom prolazu izvodi toˇcno n−

1 puta, u drugom n − 2 puta, u tre´cem n − 3 puta itd. U svakom izvrˇsavanju unutraˇsnje petlje izvede se provjera uvjeta, te ako je uvjet ispunjen, onda se elementima zamijene mjesta. U najgorem sluˇcaju, kada je lista na poˇcetku obrnuto sortirana, uvjet ´ce uvijek biti zadovoljen. Neka kontrola vanjske

petlje ima sloˇzenost c 1 , neka kontrola unutarnje petlje, zajedno s provjerom uvjeta i zamjenom mjesta elementima ima sloˇzenost c 2 . Tada je, u najgorem sluˇcaju, sloˇzenost jednaka:

X i −1

T ExchangeSort

·n + (c 1 + ) ·n−c 1 ,

iz ˇcega slijedi da je

(4.4) U najboljem sluˇcaju, kada je lista unaprijed sortirana, uvjet u koraku

T ExchangeSort

= Θ(n 2 ).

max

3 se nikada ne ispunjava, pa nema ni jedne zamjene mjesta. Neka je sa c 3

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE oznaˇceno trajanje kontrole unutarnje petlje zajedno s provjerom uvjeta u

koraku 3. Tada je

ˇsto sliˇcno gornjem raˇcunu daje

(4.5) Kako su maksimalna i minimalna sloˇzenost ovog algoritma asimptotski

T ExchangeSort

= Θ(n 2 ).

min

jednake, slijedi da je i

(4.6) Sortiranje umetanjem

Sortiranje umetanjem (engl. insertion sort) je joˇs jedan od osnovnih algo- ritama sortiranja. Ovaj se algoritam temelji na ideji dijeljenja liste na dva dijela: prvi koji je ve´c sortiran i drugi koji tek treba sortirati. Na poˇcetku se u prvom dijelu nalazi samo prvi element liste. U svakom se sljede´cem koraku uzima prvi element iz drugog dijela liste i ume´ce se na odgovaraju´ce mjesto u prvom dijelu. U prvom se koraku uzima drugi element liste te se usporeduje s prvim elementom. Ako je drugi element manji od prvoga, onda prvi i drugi element mijenjaju mjesta. Nakon toga se uzima tre´ci element, koji se usporeduje s drugim. Ako je manji, onda drugi element prelazi na tre´ce mjesto, a promatrani se element usporeduje s prvim. Ako je ve´ci od prvog, onda se ume´ce na drugo mjesto, a ako je manji, onda se prvi element pomiˇce na drugo mjesto, a promatrani dolazi na prvo mjesto. Isti se pos- tupak ponavlja za ˇcetvrti element liste i tako redom. Za svaki se element promatra sortirani dio liste. Elementi sortiranog dijela liste usporeduju se od zadnjeg prema prvome, s promatranim elementom, te se elementi ve´ci od promatranog pomiˇcu za jedno mjesto dalje u listi. Kada se naide na element manji od promatranog, onda se promatrani element stavlja iza njega s kojeg je ve´c prije toga element pomaknut za jedno mjesto dalje. Tako se sortirani dio liste pove´cava za jedan element i moˇze se prije´ci na sljede´ci element liste. Kada se svi elementi liste obrade na ovaj naˇcin, cijela ´ce lista biti sortirana.

Primjer 4.4 Sortirajmo listu

7 3 5 1 8 4 2 9 6 U prvom koraku prva dva elementa mijenjaju mjesta i dobijamo:

POGLAVLJE 4. ALGORITMI 151

U sljede´cem koraku pretraˇzujemo prva dva elementa traˇze´ci onaj koji ima ve´cu vrijednost od 5, a to je drugi element. Njega pomiˇcemo za jedno mjesto dalje a na njegovo mjesto dolazi tre´ci element.

3 5 7 1 8 4 2 9 6 Cetvrti element ima vrijednost 1 i on dolazi na poˇcetak liste, a svi se elementi ˇ

prije njega pomiˇcu za jedan element udesno:

1 3 5 7 8 4 2 9 6 Sljede´ci element ostaje na svom mjestu:

1 3 5 7 8 4 2 9 6 Prva dva elementa su manja od 4, pa ostaju gdje jesu, dok se ostali elementi

pomiˇcu za jedno mjesto udesno.

1 3 4 5 7 8 2 9 6 Sljede´ci element ide na drugo mjesto u listi.

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE

1 2 3 4 5 7 8 9 6 Sljede´ci element ostaje na svom mjestu.

1 2 3 4 5 7 8 9 6 Posljednji element ide na ˇsesto mjesto u listi.

1 2 3 4 5 6 7 8 9 Algoritam 4.9

ULAZ: Lista a 1 ,...,a n IZLAZ: Sortirana lista, koja se sastoji od istih elemenata kao i ulazna lista.

1. Izvrˇsi korake 2-4 za j := 2, . . . , n.

2. p := a j .

3. Izvrˇsi korak 4 za i := 1, . . . , j − 1.

4. Ako je a i >a j onda swap(a i ,a j ). Pogledajmo sloˇzenost ovog algoritma. U svakom sluˇcaju koraci 1 i 2

izvrˇsavaju se n − 1 puta, a svaki od njih ima konstantno trajanje. Broj prolaza kroz korake 3 i 4 pove´cava se za svaki prolaz kroz korake 1 i 2. Najgori je sluˇcaj obrnuto sortirana lista. Onda se izvrˇsava maksimalan broj zamjena elemenata. U tom ´ce sluˇcaju uvjet iz 4 uvijek biti zadovoljen. U tom sluˇcaju je sloˇzenost

n −1 inssort

c 2 ·i=c 1 ·n+c 2 ·

Sliˇcno, ako je lista ve´c sortirana, onda ´ce svaki puta uvjet iz koraka 4 biti neistinit, pa se ne´ce izvrˇsiti nijedno mijenjanje mjesta. No, sve ostale operacije ´ce se izvrˇsavati. Stoga ´ce biti

T inssort

(n) = Θ(n 2 ).

min

No, u tom je sluˇcaju i

T inssort

(n) = Θ(n 2 ).

avg

POGLAVLJE 4. ALGORITMI 153

Mjehuriˇ casto sortiranje U mjehuriˇcastom sortiranju (engl. bubble sort) prolazi se redom po elemen-

tima liste i svaki se od njih usporeduje sa svojim sljedbenikom. Ako je neki element ve´ci od sljedbenika, onda im se zamjenjuju mjesta. Nakon prvog prolaza na kraj liste ”isplivat” ´ce najve´ca vrijednost. Nakon toga se isti postupak ponavlja za prvih n − 1 elemenata, pa ´ce nakon prolaza kroz listu u predposljednji element do´ci druga najve´ca vrijednost. Tako ´ce nakon n −1 prolaza lista biti sortirana.

Primjer 4.5 Opet sortirajmo istu listu:

7 3 5 1 8 4 2 9 6 Prvo mjenjaju mjesta prvi i drugi element.

3 7 5 1 8 4 2 9 6 Nakon toga drugi i tre´ci,

3 5 7 1 8 4 2 9 6 pa tre´ci i ˇcetvrti.

3 5 1 7 8 4 2 9 6 Cetvrti i peti element ne mijenjanju mjesta, ve´c mjesta mijenjaju peti i ˇsesti ˇ

element.

3 5 1 7 4 8 2 9 6 Nakon toga, mjesta mijenjaju ˇsesti i sedmi element:

3 5 1 7 4 2 8 9 6 Sedmi i osmi element ne mijenjaju mjesta, ve´c samo osmi i deveti.

3 5 1 7 4 2 8 6 9 Time je zavrˇsen prvi prolaz kroz listu i na posljednjem se mjestu nalazi

najve´ca vrijednost. Sada se postupak ponavlja za prvih n − 1 elemenata. Mijenjaju se drugi i tre´ci element,

3 1 5 7 4 2 8 6 9 pa ˇcetvrti i peti, a nakon toga peti i ˇsesti.

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE Na kraju ovog koraka mijenjaju se sedmi i osmi element

3 1 5 4 2 7 6 8 9 U sljede´cem se prolazu obraduje prvih sedam elemenata

Mijenja se prvi i drugi,

1 3 5 4 2 7 6 8 9 pa tre´ci i ˇcetvrti te ˇcetvrti i peti element.

1 3 4 2 5 7 6 8 9 Na kraju ovog koraka se mijenjaju ˇsesti i sedmi element.

1 3 4 2 5 6 7 8 9 U sljede´cem se prolazu mijenjaju samo tre´ci i ˇcetvrti element.

1 3 2 4 5 6 7 8 9 Sada se promatra prvih pet elemenata liste, no u ovom se prolazu mijenjaju

samo drugi i tre´ci element.

1 3 2 4 5 6 7 8 9 U sljede´cem se prolazu promatraju prva ˇcetiri elementa liste, no mijenjaju

se samo drugi i tre´ci.

1 2 3 4 5 6 7 8 9 Iako smo time dobili sortiranu listu, algoritam ´ce izvesti joˇs dva prolaza kroz

listu, za prva tri te za prva dva elementa liste. Algoritam 4.10

ULAZ: Lista a 1 ,...,a n IZLAZ: Sortirana lista, koja se sastoji od istih elemenata kao i ulazna lista.

1. Ponavljaj korake 2-3 za i = 1, . . . , n − 1.

2. Ponavljaj korak 3 za j = 1, . . . , n − i.

3. Ako je a j >a j +1 onda swap(a j ,a j +1 ).

POGLAVLJE 4. ALGORITMI 155

Neka je a k najve´ci element u listi. Kada algoritam naide u prvom prolazu na taj element, on ´ce biti ve´ci od svakog sljede´ceg elementa u listi, pa ´ce s njime mijenjati mjesta. Na kraju prolaza, taj ´ce element biti na kraju liste. U drugom ´ce se koraku na isti naˇcin na pretposljednjem mjestu na´ci drugi najve´ci element i tako redom. To dokazuje da je ovaj algoritam korektan.

Ocijenimo sada njegovu sloˇzenost. Bez obzira kako izgleda instanca pro- blema, korak 1 ´ce se ponavljati n − 1 puta. U prvom ´ce se prolazu koraci

2 i 3 ponavljati n − 1 puta, a u svakom ´ce sljede´cem prolazu njihov broj ponavljanja biti za jedan manji. Najgori je sluˇcaj kada je uvjet iz koraka

3 uvijek ispunjen (kada je lista na poˇcetku obrnuto sortirana). U tom ´ce se sluˇcaju svaki puta izvrˇsavati naredba swap. Najbolji je sluˇcaj kada ovaj uvjet nije ispunjen ni jednom (kada je lista na poˇcetku ve´c bila sortirana). Tada se naredba swap ne´ce izvrˇsiti ni jednom, no broj provjera uvjeta u tom koraku ne´ce se promijeniti. Iz toga zakljuˇcujemo da ´ce najgori i najbolji sluˇcaj za ovaj algoritam biti asimptotski jednaki.

(4.7) Iz gornjeg razmatranja zakljuˇcujemo da je i

= Θ(n 2 )

(n) = Θ(n 2 ). Primijetili smo da je algoritam izveo svih osam koraka, iako je sortiranje

T bubsort

liste bilo gotovo ve´c nakon ˇsestog koraka. Poboljˇsanje ovog algoritma se moˇze posti´ci ako se u njega ugradi provjera, koja ´ce provjeravati je li u nekom prolazu napravljena zamjena, a ako to nije sluˇcaj, ono ´ce zaustavljati algoritam.

Sortiranje spajanjem Sortiranje spajanjem (engl. merge sort) je prvi algoritam koji ´cemo ovdje

opisati, a koji ima sloˇzenost manju od kvadratne. Vidjet ´cemoda je sloˇzenost ovog algoritma jednaka O(n lg n). Algoritmi sortiranja s takvom sloˇzenoˇs- ´cu najˇceˇs´ce koriste metodu podijeli pa ovladaj (engl. divide and conquer). Podijeli pa ovladaj je metoda kod koje se problem reducira na jedan ili viˇse problema istog tipa, ali manjih dimenzija, a rjeˇsenje originalnog problema dobija se kompozicijom rjeˇsenja reduciranih problema. Sortiranje spajanjem

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE koristi algoritam za spajanje dvije sortirane liste u jednu, isto tako, sortiranu

listu. Algoritam 4.11 (Merge)

ULAZ: Dvije sortirane liste b 1 ,...,b k ic 1 ,...,c l

IZLAZ: Sortirana lista a 1 ,...,a k +l , koja se sastoji od elemenata ulaznih listi.

1. i := 1, j := 1.

2. Ponavljaj korak 3 sve dok je i ≤ k i j ≤ l.

3. Ako je b i <c j onda a i +j−1 := b i , i := i+1 inaˇce a i +j−1 := c j , j := j+1.

4. Ponavljaj korak 5 sve dok je i ≤ k.

5. a i +j−1 := b i , i := i + 1.

6. Ponavljaj korak 7 sve dok je j ≤l

7. a i +j−1 := c j , j := j + 1. Priliˇcno je jasno da ovaj algoritam zaista spaja dvije sortirane liste u

sortiranu listu. Ocijenimo njegovu sloˇzenost. Neka su k i l duljine ulaznih lista.

Korak 1 ´ce se izvrˇsiti jednom. Nadalje, za svaki element ulaznih listi, izvrˇsit ´ce se jedan od blokova naredbi iz koraka 3 ili blok naredbi iz koraka

5 ili pak iz koraka 7. Pogledamo li paˇzljivije vidjet ´cemo da su svi ti blokovi sliˇcni i da imaju istu, konstantnu sloˇzenost. Provjeravat ´ce se uvjet iz koraka

2 i 3 ili uvjet iz 4 ili pak 6. Sva se ta tri uvjeta mogu odozgo ograniˇciti nekom konstantom, pa je sloˇzenost spajanja

T merge max (k, l) ≤c 1 + (k + l) · (c 2 +c 3 )

= O(k + l)

Na sliˇcan se naˇcin vidi da je

T merge

T merge

avg

(n) = O(k + l).

Algoritam sortiranja spajanjem dijeli ulaznu listu na dvije podjednako duge podliste, sortira ih te ih algoritmom za spajanje spaja u jednu sortiranu listu. Svaka se od podlista sortira na isti naˇcin. Tako se problem smanjuje dok se ne dode do jednoˇclanih listi. Sortiranje jednoˇclane liste je trivijalno, tj. svaka jednoˇclana lista je ve´c sortirana.

POGLAVLJE 4. ALGORITMI 157

Algoritam 4.12 ULAZ: Lista a 1 ,...,a n IZLAZ: Sortirana lista, koja se sastoji od istih elemenata kao i ulazna lista.

1. Sortiraj listu a 1 , . . . , a⌊ n 2 ⌋.

2 ⌋ +1 ,...,a n 2. Sortiraj listu a⌊ .

3. Spoji a 1 n

,...,a , . . . , a⌊ n 2 ⌋ i a⌊ . 2 ⌋ +1

Algoritam ima sljede´cu sloˇzenost:

merge ln m jn k T max

mersort ln m

mersort

(n) ≤2·T max ( )+T max ( , )

mersort ln m ≤2·T max (

)+d 1 ·n+d 2 .

Napiˇsemo li to kako je to uobiˇcajeno za rekurzije imat ´cemo:

t n =2 ·t n 2 +d 1 ·n+d 2 . Uvodimo supstituciju s n =t 2 n i imamo:

2 n−1 +d 1 ·2 +d 2 =s n −1 +d 1 ·n+d 2

Oduzmimo jednadˇzbu za (n − 1)-vi ˇclan od jednadˇzbe za n-ti ˇclan:

n −s n −1 = 2 ·s n −1 −2·s n −2 +2 −1 ·d 1

Iz toga slijedi

s n =3 ·s n −1 −2·s n −2 +2 ·d 1 .

Nadalje, duzmimo formulu za (n − 1)-vi ˇclan pomnoˇzenu s 2 od formule za n-ti ˇclan.

s n = 3 ·s n n −1 −2·s n −2 +2 ·d 1

2 n ·s

n −1

= 6 ·s n −2 −4·s n −3 +2 ·d 1 s n −2·s n −1 = 3 ·s n −1 −8·s n −2 +4 ·s n −3

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE odnosno,

s n =5 ·s n −1 −8·s n −1 +4 ·s n −3 .

Cime smo dobili homogeu rekurziju. Karakteristiˇcna jednadˇzba ove rekurzije ˇ je

x 3 − 5x 2 + 8x − 4 = 0.

Ova jednadˇzba ima dvostruki korijen x 1,2 = 2 i jednostruki korijen x 3 = 1. Dakle op´ce rjeˇsenje ove jednadˇzbe je

n =C 1 ·2 +C 2 ·n·2 +C 3 ·1 . Konaˇcno, dobivamo da je

=C n

1 ·2 +C 2 ·n·2 +C 3 .

iz ˇcega slijedi da je

t n =C 1 ·n+C 2 · ·n lg n + C 3 .

Drugim rijeˇcima,

T M ergesort

max

= O(n lg n).

Ovaj algoritam nije osjetljiv na razliˇcitosti instanci. Kakva god bila instanca, algoritam ´ce imati jednaku sloˇzenost. Stoga je

= O(n lg n). Primije´cuje se jedan nedostatak sortiranja spajanjem naspram drugih dosa-

T M ergesort

M ergesort

=T avg

min

da opisanih algoritama sortiranja: sortiranje spajanjem za svoj rad treba do- datno polje, odnosno dodatni memorijski prostor. Nijedan od dosad opisanih algoritama, osim sortiranja spajanjem, nema taj nedostatak.

Sortiranje pomo´ cu hrpe Sortiranje pomo´cu hrpe (engl. heapsort) je vrlo interesantan algoritam. Za

razliku od svih dosad prikazanih algoritama, ovaj se algoritam temelji na posebnom apstraktnom tipu podataka - hrpi.

Hrpa je puno binarno stablo, kako je to opisano u sljede´cem poglavlju, sa svojstvom da vrh ima manju vrijednost od oba svoja djeteta. Hrpa se puni redom, tako da su joj sve razine, osim posljednje, u potpunosti popu- njene. Povrh toga, posljednja se razina puni s lijeva na desno. Zbog toga, pri dodavanju i brisanju elemenata treba paziti da sva svojstva hrpe budu zadovoljena.

Sada ´cemo opisati algoritme za dodavanje i brisanje elemenata u hrpi.

POGLAVLJE 4. ALGORITMI 159

Algoritam dodavanja elemenata u hrpu je sljede´ci: novi se element do- daje na najljevije slobodno mjesto na posljednjoj razini stabla. Nakon toga se usporeduje njegova vrijednost s vrijednoˇs´cu njegovog roditelja. Ako je vrijednost novododanog elementa manja od vrijednosti njegovog roditelja, onda im mijenjamo mjesto. Nakon toga provjeravamo novododani element, koji je sada na pretposljednjoj razini s njegovim trenutnim roditeljem, itd. Ovaj postupak ponavljamo sve dok novododani element ne dobije roditelja, koji je manji od njega, ili dok ne postane korijen stabla.

Primjer 4.6 Stavit ´cemo listu koju smo i ranije koristili u hrpu.

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE

9 7 Slika 4.4

Najefikasnija implementacija hrpe je ona pomo´cu polja. Stavimo li ko- rijen u element polja s indeksom 1, te ako lijevo dijete ˇcvora upisanog u element polja s indeksom n stavimo u element s indeksom 2 · n, a desno dijete u element s indeksom 2 · n + 1, onda ´ce svaki element imati svoje mjesto u polju. Takoder, zbog toga ˇsto je hrpa potpuno stablo, u kojem se posljednja razina puni s lijeva na desno, elementi hrpe ´ce popunjavati elemente polja redom.

Algoritam 4.13 ULAZ: Hrpa H : h 1 ,...,h n i element x IZLAZ: Hrpa H ′ koja se sastoji od elemenata stoga S i elementa x.

1. Stavi x u polje u element h[n + 1]. i := n + 1.

2. dok je i > 1 i dok je h[i] < h[ ¥ i ¦

2 ] radi korak 3.

¥ i ¦ ¥ i 3. swap(h[i], h[ ¦

2 ]), i := 2 .

Jasno je da ovakav algoritam dodavanja novih vrhova u hrpu odrˇzava sva svojstva hrpe. Pogledajmo njegovu sloˇzenost. Neka je n broj elemenata u hrpi. Jasno je da, poˇsto je potpuna, hrpa od n elemenata ima visinu 1 +

⌊log 2 n ⌋. Kako algoritam mijenja element s elementom prethodne razine, on moˇze izvrˇsiti toˇcno ⌊log 2 n ⌋ zamjena, odnosno koraci od 2 do 3 se ponavljaju najviˇse ⌊log 2 n ⌋ puta. Dakle sloˇzenost ovog algoritma je

T InsHeap

(n) ≤c 1 +c 2 · ⌊log 2 n ⌋

max

= O(lg n).

S druge strane, najbolji sluˇcaj je kada je dodani element odmah ve´ci od svog roditelja. U tom sluˇcaju se korak 2 ponavlja jednom, a 3 ni jednom. Stoga imamo

POGLAVLJE 4. ALGORITMI 161

T InsHeap

Bez obzira na to gdje ´ce novododani element na kraju zavrˇsiti, algoritam ´ce se kroz stablo kretati istim putem. Stoga pretpostavimo da je jednako vjerojatno da ´ce novododani element ostati na svakoj od razina stabla. Tada

ta vjerojatnost iznosi 1 ⌊log 2 n ⌋ , pa je sloˇzenost prosjeˇcnog sluˇcaja

⌊log 2 n

·i·c 2

⌊log 2 n ⌋

i =1

1 ⌊log 2 n ⌋ · (⌊log 2 n ⌋ + 1)

· (⌊log 2 n ⌋ + 1) = O(lg n)

Jedno vaˇzno svojstvo hrpe jest to ˇsto se najmanji element hrpe uvijek nalazi u njenom korijenu. Odatle proizlazi ideja sortiranja pomo´cu hrpe - iz hrpe se izvadi korijen, stavi se na poˇcetak liste, a ostatak hrpe se ponovno preuredi tako da zadovoljava sva svojstva hrpe.

Postupak praˇznjenja hrpe je sljede´ci. Iz hrpe se vrijednost korijena pre- seli u izlaznu listu. Nakon toga se vrijednost najdesnijeg elementa na zadnjoj razini hrpe preseli u korijen a posljednji se element hrpe obriˇse. Time je sta- blo ostalo potpuno. Joˇs je potrebno osigurati uredaj u hrpi. Promatrana vrijednost, koja naruˇsava uredaj u hrpi nalazi se u korijenu. Usporedimo tu vrijednost s manjim od djece korijena te ako je promatrana vrijednost ve´ca, zamjenimo im mjesta. I dalje se promatrana vrijednost, sada smjeˇstena na drugoj razini stabla, usporeduje s manjim svojim djetetom. Ovaj se pos- tupak ponavlja sve dok promatrana vrijednost ne bude manja od manjeg djeteta (pa onda i od ve´ceg) ili dok se promatrana vrijednost ne nade u ˇcvoru bez djece. Sljede´ci primjer pokazuje kako se prazni hrpa i kreira sor- tirana lista.

Primjer 4.7 Ispraznimo hrpu iz prethodnog primjera i kreirajmo sortiranu listu.

162

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE

POGLAVLJE 4. ALGORITMI 163

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE

Slika 4.5

Algoritam 4.14 ULAZ: Hrpa H : h 1 ,...,h n IZLAZ: Hrpa H ′ koja je dobijena iz hrpe H izbacivanjem vrijednosti koja se nalazila u korijenu.

1. h[1] := h[n]. p := h[n]. Izbaci element h[n], i := 1

POGLAVLJE 4. ALGORITMI 165

2. Radi korake od 3 do 4 sve dok je 2 · i ≤ n i (h[i] < h[2 · i] ili je h[i] < h[2 · i]).

3. Ako je h[2 · i] ≤ h[i · i + 1], onda swap(h[i], h[2 · i]).

4. Ako je h[2 · i] > h[i · i + 1]- onda swap(h[i], h[2 · i + 1]).

5. Vrati p. Ovaj algoritam mijenja promatrani element s onim na sljede´coj razini.

Stoga se koraci od 2 do 4 mogu ponoviti najviˇse ⌊log 2 n ⌋ puta. Stoga je njegova sloˇzenost:

T DelHeap

(n) ≤c 1 +c 2 · ⌊log 2 n ⌋

max

= O(lg n)

U najboljem ´ce sluˇcaju prebaˇceni element ostati korijen i ne´ce prolaziti kroz stablo. U tom je sluˇcaju sloˇzenost

T DelHeap

Nadalje, vrlo sliˇcno kao i kod punjenja zakljuˇcuje se da je

T DelHeap

avg

(n) = O(lg n).

I na kraju, algoritam sortiranja pomo´cu hrpe ˇcita redom elemente liste

i stavlja ih u hrpu. Nakon ˇsto se svi elementi liste nadu u hrpi, poˇcinje praˇznjenje hrpe. Kako se elementi izbacuju iz hrpe tako se redom upisuju natrag u listu. Nakon ˇsto se hrpa isprazni, lista ´ce biti sortirana.

Algoritam 4.15 ULAZ: Lista a 1 ,...,a n IZLAZ: Sortirana lista koja se sastoji od istih elemenata kao i ulazna lista.

1. Za i := 1, . . . , n radi korak 2.

2. InsHeap(a i ).

3. Za i := 1, . . . , n radi korak 4.

4. a i := DelHeap.

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE Jasno je da se u svakom sluˇcaju koraci od 1 do 2, te koraci od 3 do 4

izvode n puta, pri ˇcemu je n duljina ulazne liste. Sloˇzenost algoritama za umetanje elemenata u hrpu i brisanje elemenata iz hrpe izraˇcunata je ranije, pa imamo:

X DelHeap T max

HeapSort

X InsHeap

Sliˇcno se dobija i da je

T HeapSort

(n) = O(n lg n).

avg

I na kraju,

X DelHeap T min

HeapSort

X InsHeap

= O(n).

Ovako izvedeno sortiranje pomo´cu hrpe ima istu manu koju smo spome- nuli kod sortiranja spajanjem - potreban je dodatni memorijski prostor za hrpu u kojoj mora biti mjesta za joˇs jednu kopiju svakog elementa ulazne liste. Moˇze li se to izbje´ci? Za razliku od sortiranja spajanjem, sortiranje pomo´cu hrpe se moˇze izvesti prirodno i bez dodatnog prostora. Polje u kojem su smjeˇsteni elementi moˇze se koristiti ujedno i kao hrpa. Kako?

Kao prvo, potrebno je malo predefinirati hrpu. Hrpa kakvu smo do sada rabili bila je tzv. min-hrpa, tj. hrpa u kojoj je oznaka roditelja manja od oznaka njegove djece, tj. u kojoj se u korijenu nalazi najmanji element hrpe. Max-hrpa se definira obrnuto. Oznaka roditelja u njoj mora biti ve´ca od oznaka njegove djece. U takvoj hrpi u korijenu ´ce se nalaziti najve´ci element u hrpi. Primjer ovakve hrpe za listu iz naˇseg prethodnog primjera je

POGLAVLJE 4. ALGORITMI 167

1 6 Slika 4.6

Ovakva se hrpa moˇze izvesti u samom polju koje sadrˇzi ulazne podatke. Kre´ce se od prvog elementa. Nakon toga se promatra drugi element polja

i na ve´c ranije opisani naˇcin, uz zamjenu usporedbe, prva se dva elementa pretvore u hrpu. Nakon toga se promatra tre´ci element u polju i iz prva tri elementa se, na ranije opisani naˇcin, stvori hrpa, itd. Tako se radi sve dok svi elementi polja ne ˇcine hrpu. Nakon toga ´ce se u korijenu nalaziti najve´ci element. Brisanje elemenata iz hrpe ide na isti naˇcin kao i ranije, samo ˇsto se obrisani element ne stavlja u posebno polje, ve´c korijen mijenja mjesto s posljednjim elementom u polju. Nakon toga je sigurno da je element, koji je bio u korijenu, stavljen na svoje zavrˇsno mjesto u polju, tj. na posljednje mjesto, pa se broj elemenata u hrpi smanjuje za 1, i hrpa se preureduje tako

da zadovoljava sva traˇzena svojstva. Ovaj je postupak isto tako ve´c opisan ranije. Dakle, postupak je sljede´ci:

Algoritam 4.16 ULAZ: Lista a 1 ,...,a n IZLAZ: Sortirana lista koja se sastoji od istih elemenata kao i ulazna lista.

1. Za i := 1, . . . , n radi korake 2-4.

2. j = i.

3. Sve dok je (i > 1) ∧ (a[i/2] < a[i]) radi korak 4.

4. swap(a[i], a[i/2]).

5. i := n.

6. Sve dok i > 1 radi korake 7-17.

7. swap(a[1], a[i]).

8. i := i − 1.

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE

9. j := 1.

10. Sve dok je (2 · j + 1 ≤ i) ∧ (max(a[2j], a[2j + 1]) > a[j]) radi korake 11-16.

11. if a[2 · j] > a[2 · j + 1] radi korake 12-13.

12. swap(a[j], a[2 · j]).

13. j := 2j.

14. Inaˇce radi korake 15-16.

15. swap(a[j], a[2 · j + 1]).

16. j := 2 · j + 1.

17. Ako je (2 · j ≤ i) ∧ (a[2 · j] > a[j]) onda swap([a[j], a[2 · j]). Sloˇzenost ovog algoritma ista je kao i sloˇzenost originalnog algoritma za

sortiranje pomo´cu hrpe. Naime, ovo je u biti isti algoritam kao i prethodni, samo s manje koriˇstenog memorijskog prostora.

Quicksort algoritam Sada ´cemo obraditi algoritam sortiranja koji danas predstavlja jedan od

vrhunaca algoritama za sortiranje. Promiˇsljanjem kako bi se mogao ubrzati algoritam sortiranja spajanjem te izbje´ci potrebu za upotrebom pomo´cnog polja, nastao je ovaj algoritam. Naime, kod algoritma sortiranja spajanjem, sortiranje se vrˇsi u dvije faze: dijeljenje liste na manje podliste, te spajanje podlista u sortiranu listu. Pokuˇsaji ubrzanja faze dijeljenja liste doveli su do algoritma prirodnog sortiranja spajanjem (natural merge sort) ([6] str 161-163), dok je pokuˇsaj ubrzanja faze spajanja doveo do potpuno novog algoritma sortiranja - quicksort algoritma. Quicksort algoritam, kao i algo- ritam sortiranja spajanjem, temelji se na metodi podijeli pa ovladaj, no kod njega je faza spajanja u potpunosti izbjegnuta.

Kao prvo, potrebno je istaknuti jedan element liste - tzv. pivot element. Za pivot element se moˇze uzeti prvi element liste, srednji izmedu prva tri ili ga se moˇze izraˇcunati na bilo koji drugi naˇcin. Jedino ˇsto je vaˇzno jest

da se pivot mora izraˇcunati u vremenu O(1). Nakon toga se elementi u listi preslaguju tako da u prvom dijelu liste budu elementi koji su manji od pivota,

a u drugom dijelu liste elementi ve´ci od pivota. Nakon toga se algoritam izvodi rekurzivno za prvi i drugi dio liste. Postupak se ponavlja sve dok lista nema manje od dva elementa, a tada sortiranje postaje trivijalno.

Primijetimo da nakon ˇsto su elementi u podlistama sortirani nije po- trebno nikakvo spajanje. Naime, zbog preuredenja polja, svi su elementi u drugom dijelu liste ve´ci od svakog elementa iz prvog dijela liste.

POGLAVLJE 4. ALGORITMI 169

Prije negoli prikaˇzemo primjer sortiranja liste ovim algoritmom potrebno je razrijeˇsiti neke tehniˇcke detalje izvedbe. Toˇcnije, potrebno je re´ci kako ´ce se vrˇsiti premjeˇstanje elemenata liste? Za to su potrebna dva kursora, od kojih ´ce prvi biti iniciran na drugi element liste i rasti, a drugi ´ce biti iniciran na posljednji element liste i padati. Neka je pivot prvi element liste. Promatramo preostale elemente liste redom. Ako je promatrani ele- ment (onaj na kojeg pokazuje prvi kursor) manji od pivota, prvi se kursor pomiˇce za jedan element dalje. Ako je ve´ci od pivota, tada se prelazi na pretraˇzivanje liste odzada. Pretraˇzuje se lista odzada sve dok se ne pronade element manji od pivot elementa. Nadenim se elementima promijene mjesta

i nastavlja se traˇziti od prvog kursora. Pretraˇzivanje zavrˇsava kada prvi kur- sor premaˇsi drugi. Zanimljivo je da ´ce u trenutku kada se prvi kursor nade iza drugoga, drugi kursor pokazivati toˇcno na ono mjesto u listi na kojem ´ce se nalaziti pivot kada ´ce lista biti sortirana. Kako se pivot element, prema naˇsem algoritmu, sada nalazi na poˇcetku promatranog dijela liste, potrebno je zamijeniti pivot element s onim elementom na koji pokazuje drugi kursor. Nakon toga je potrebno odvojeno ponoviti postupak sortiranja za elemente koji se nalaze do kursora i one koji se nalaze iza kursora. Kursor viˇse nije potrebno obradivati jer se on, kao ˇsto smo ve´c rekli, nalazi na mjestu na kojem ´ce se nalaziti i u sortiranoj listi.

Primjer 4.8 Sortirajmo opet istu listu quicksort algoritmom. Za pivot element se uzima prvi element u listi.

7 3 5 1 8 4 2 9 6 Pivot element je element s vrijednoˇs´cu 7. Pretraˇzuje se lista od poˇcetka

i traˇzi se vrijednost ve´ca od pivota. Prva je takva vrijednost broj 8. Sa straˇznje strane liste traga se za elementom s vrijednoˇs´cu manjom od pivota. To je element s vrijednoˇs´cu 6.

7 3 5 1 8 4 2 9 6 Zamijenimo mjesta tim dvama elementima.

7 3 5 1 6 4 2 9 8 Traˇzimo dalje. Sljede´ci element s ve´com vrijednoˇs´cu od pivota je element

s vrijednoˇs´cu 9. S druge strane, sljede´ci element s vrijednoˇs´cu manjom od pivota je element s vrijednoˇs´cu 2. U tom je trenutku drugi kursor preˇsao ispred prvog i ovaj se dio algoritma zavrˇsava. Sada se lista dijeli na dva dijela - od poˇcetka liste pa do drugog kursora, te od prvog kursora do kraja.

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE Kako je pivot najve´ci u prvom dijelu, on se stavlja na kraj prvog dijela, te

se postupak ponavlja za sve elemente do njega, dok se pivot element sigurno nalazi na onom mjestu gdje ´ce se na´ci i u sortiranoj listi, pa njega ne treba viˇse dirati. Sada se postupak ponavlja na prvom i na drugom dijelu.

2 3 5 1 6 4 7 9 8 Pogledajmo prvi dio. Pivot je broj 2. Promatrano sprijeda, prvi element

ve´ci od pivota je element s vrijednoˇs´cu 3. Straga, prvi element s vrijednoˇs´cu manjom od pivota je onaj koji ima vrijednost 1. Mijenjamo im mjesta.

2 1 5 3 6 4 7 9 8 Daljnje pretraˇzivanje sprijeda ´ce se zaustaviti na sljede´cem elementu, s vri-

jednoˇs´cu 5. Pretraˇzivanje odostraga ´ce opet stati na broju 1, te ´ce u tom trenutku opet prvi kursor prije´ci iza drugoga. Mijenjamo pivot sa zadnjim elementom u prvom dijelu, tj., u ovom sluˇcaju, 2 i 1.

1 2 5 3 6 4 7 9 8 Sada promatramo posljednja dva elementa. Pivot je element s vrijednoˇs´cu

9. Traˇze´ci sprijeda element ve´ci od pivota, prije´ci ´cemo posljednji element liste i u tom trenu prvi kursor ´ce prije´ci iza drugog. Pivot mijenja mjesto s posljednjim u prvom dijelu, ˇcime dobivamo

1 2 5 3 6 4 7 8 9 Sada promatramo jedini preostali niz koji je preostao, koji je dulji od jednog

elementa. Pivot ´ce biti element s vrijednoˇs´cu 5. Pretraga sprijeda staje na elementu s vrijednoˇs´cu 6, a straga na elementu s vrijednoˇs´cu 4.

1 2 5 3 6 4 7 8 9 Mijenjamo im mjesta.

1 2 5 3 4 6 7 8 9 Daljnja pretraga sprijeda ´ce zavrˇsiti na broju 6, a pretragom straga ´cemo

prije´ci ispred prvog kursora. Pivot mijenja mjesto s elementom s vrijednoˇs´cu

POGLAVLJE 4. ALGORITMI 171

Preostao je joˇs jedan segment polja, koji ima viˇse od jednog elementa, i njega takoder sortiramo. Pivot je element s vrijednoˇs´cu 4. Pretraga sprijeda ´ce prije´ci posljednji element promatranog segmenta. Pivot mijenja mjesto s elementom na kojeg pokazuje drugi kursor, ˇcime se dobije:

1 2 3 4 5 6 7 8 9 odnosno sortirana lista. Algoritam 4.17

ULAZ: Lista a 1 ,...,a n i kursori i i j na poˇcetak, odnosno na kraj dijela polja koji sortiramo IZLAZ: Sortirana lista koja se sastoji od istih elemenata kao i ulazna lista.

1. k := i + 1, l := j.

2. Sve dok je k <= l radi korake 3-5.

3. Dok je ((k <= l) ∧ (a i >= a k )) k := k + 1.

4. Dok je ((k <= l) ∧ (a i <= a l )) l := l − 1.

5. Ako je k < l swap(a k ,a l ).

6. Ako je l > i swap(a i ,a l ).

7. Ako je l > i Quicksort(a, i, l − 1).

8. Ako je k < j Quicksort(a, k, j). Najgori sluˇcaj za ovaj algoritam je kada je lista ve´c unaprijed sortirana

ili ako je sortirana obrnutim redosljedom. U tim ´ce se sluˇcajevima, u svakom prolazu lista dijeliti na podlistu od jednog elementa i podlistu koja sadrˇzi sve elemente osim jednog. Korak 1 ima konstantnu sloˇzenost. Koraci od 2

do 5 imaju sloˇzenost c 2 +c 3 · n. Sloˇzenost koraka 6 je konstantna. Stoga je sloˇzenost Quicksorta u najgorem sluˇcaju

T Quicksort

Quicksort

max

(n) = c 1 +c 2 +c 3 ·n+c 4 +T max (n − 1)

=T Quicksort

max

(n − 1) + d 1 ·n+d 2

Standardni zapis ove rekurzije je

t n =t n −1 +d 1 ·n+d 2 .

Oduzmemo li od jednadˇzbe za n-ti element niza jednadˇzbu za n − 1-vi dobit ´cemo:

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE

t n = t n −1 +d 1 ·n+d 2 t n −1 = t n −2 +d 1 · (n − 1) + d 2

t n −t n −1 = t n −1 −t n −2 +d 1

Drugim rijeˇcima, dobivamo rekurziju

t n =2 ·t n −1 −t n −2 +d 1 .

Oduzmemo li od ove jednadˇzbe jednadˇzbu za (n −1)-vi element niza, imamo:

t n = 2 ·t n −1 −t n −2 +d 1 t n −1 = 2 ·t n −2 −t n −3 +d 1 t n −t n −1 = 2 ·t n −1 −3·t n −2 +t n −3

tj, dobivamo homogenu rekurziju

t n =3 ·t n −1 −3·t n −2 +t n −3 .

Karakteristiˇcna jednadˇzba ove rekurzije je

3 x 2 − 3x + 3x − 1 = 0.

Ova jednadˇzba ima jedan trostruki korijen x 1,2,3 = 1. Dakle, op´ce rjeˇsenje ove rekurzije je

n =C 1 ·1 +C 2 ·n·1 +C 3 ·n ·1 , odnosno,

t n =C

1 +C 2 ·n+C 3 ·n .

Najbolji mogu´ci sluˇcaj za ovaj algoritam je kada je svaki izabrani pivot srednja vrijednost elemenata dijela liste koji se promatra. U tom se sluˇcaju lista dijeli na dva podjednako dugaˇcka dijela. Sloˇzenost u tom sluˇcaju iznosi

Quicksort

Quicksort jn k

T min

(n) ≤2·T max

)+d 1 ·n+d 2 .

Dakle, u standardnom obliku

t n ≤2·t n 2 +d 1 ·n+d 2 . Uvedemo li supstituciju s n =t 2 n i onda imamo

POGLAVLJE 4. ALGORITMI 173

Oduzmemo li od formule za n-ti ˇclan niza formulu sa (n − 1)-vi ˇclan niza imat ´cemo

= 2 ·s n −1 +d 1 ·2 +d 2 s n −1 = 2 ·s n n −2 +d 1 ·2 −1 +d 2

·s n −1 −2·s n −2 +d 1 ·2 −1 , odnosno,

s n −s n −1 = 2 n

. Od ove formule oduzmemo dvostruku formulu za (n − 1)-vi ˇclan i dobijamo

n =3 ·s n −1 −2·s n −2 +d

homogenu rekurziju

s n = 3 ·s n −1 −2·s n

= 6 ·s n −2 −4·s n −3 +d 1 ·2 −1 s n −2·s n −1 = 3 ·s n −1 −8·s n −2 +4 ·s n −3

n −1

odnosno,

s n =5 ·s n −1 −8·s n −2 +4 ·s n −3 .

Karakteristiˇcna jednadˇzba ove formule je

x 3 − 5x 2 + 8x − 4 = 0.

Ova jednadˇzba ima jednostruki korijen x 1 = 1 te dvostruki korijen x 2,3 = 2. Dakle, op´ce rjeˇsenje ove jednadˇzbe je

n =C 1 ·1 +C 2 ·2 +C 3 ·n·2 . Konaˇcno,

=C n

1 +C 2 ·2 +C 3 ·n·2 .

Iz posljednje formule slijedi da je

t n =C 1 +C 2 ·n+C 3 · n · log 2 n.

Dakle, u najboljem je sluˇcaju

T Quicksort

= O(n · lg n).

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE Preostao nam je joˇs prosjeˇcan sluˇcaj. Pretpostavimo da je svaki raspored ele-

menata polja jednako vjerojatan. Da bismo pojednostavili raˇcun sloˇzenosti prosjeˇcnog sluˇcaja, ne´cemo brojiti sve operacije koje algoritam radi, ve´c samo operacije usporedivanja nad elementima polja. Lako se moˇze vidjeti

da frekvencija ostalih operacija ovisi upravo o broju usporedivanja. Pret- postavljamo da su svi elementi u polju razliˇciti, te da je jednaka vjerojatnost izbora svakog elementa polja za pivota.

Promotrimo segment polja a m ,...,a p . Kako je jednako vjerojatno da ´ce za pivot element biti uzet i-ti element po veliˇcini za svaki i = 1, . . . , p −m+1, prolaz Quicksorta ´ce podijeliti polje na polja a m ,...,a m +i−2 ia m +i ,...,a p s vjerojatnoˇs´cu

1 p −m+1 . Dakle, sloˇzenost u prosjeˇcnom sluˇcaju bit ´ce dana s

T Quicksort

Quicksort

1 X Quicksort

Pri tome je n+1 broj usporedbi koje algoritam radi prije rekurzivnog poziva. Dakle, imamo rekurziju

(t i −1 +t n −i ) + n + 1.

n i =1

Pomnoˇzimo li ovu jednadˇzbu s n dobivamo

U prethodnoj formuli zamijenimo n s n − 1 te oduzmemo tako dobivenu formulu od gornje formule:

n ·t n − (n − 1) · t n −1 = 2t n −1 +n · (n + 1) − n · (n − 1) Iz toga slijedi da je

n ·t n = (n + 1) ·t n −1 +2 · n.

Podijelimo li jednadˇzbu s n(n + 1), dobit ´cemo

POGLAVLJE 4. ALGORITMI 175

Primijenimo li ponovo formulu 4.8 za t n −1 imat ´cemo t n

No, poznato je da je

n +1

X Z 1 +1 1

dx = ln(n + 1) − ln 2

i =3 i

iz ˇcega slijedi da je T Quicksort

≤ 2 · (n + 1)[ln(n + 2) − ln 2] tj.

avg

t n = O(n · lg n).

Treba napomenuti da je Quicksort, kao ˇsto i njegovo ime kaˇze, u praksi brz za ve´cinu sluˇcajeva. No, pri tome treba imati na umu nekoliko stvari. Prva je da Quicksort ima sloˇzenost najgoreg sluˇcaja O(n 2 ), pa se moˇze desiti

da za neke instance Quicksort bude spor. Osim toga, izvedba Quicksorta je sloˇzenija od izvedbe, npr., sortiranja umetanjem. Time se ˇzeli re´ci da su konstante koje se javljaju u formuli vremenske sloˇzenosti Quicksorta, znatno ve´ce od konstanti koje se javljaju u nekim drugim algoritmima sortiranja, npr. u sortiranju umetanjem. To se ne vidi u krajnjoj asimptotskoj ocjeni sloˇzenosti, ali ´ce to znatno utjecati na brzinu rada kod instanci manje duljine. Stoga ´ce algoritam sortiranja umetanjem biti znatno brˇzi za male liste (do otprilike 20 elemenata), dok ´ce Quicksort svoju nadmo´c pokazivati tek na velikim listama (viˇse od 100000 elemenata).

Glavni nedostatak Quicksorta je, kao ˇsto je ve´c reˇceno, njegova sloˇzenost u najgorem sluˇcaju. Ovaj je problem posebno izraˇzen jer se najgori sluˇcaj postiˇze u potpuno sortiranom i obrnuto sortiranom polju. Drugim rijeˇcima, algoritam ´ce imati tendenciju da loˇsije radi ako je na poˇcetku polje uredenije,

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE

a vrlo ˇcesto ´ce upravo tako i biti. Naime, podaci su vrlo ˇcesto djelomiˇcno sortirani. Drugim rijeˇcima, ˇcesto distribucija instanci problema sortiranja nije uniformna. Kako bi se ovaj problem umanjio u stvarnoj izvedbi Quick- sorta pivot se pokuˇsava na razne naˇcine ”pametnije” izabrati. Jedna je ideja

da se pivot izabere kao srednji po veliˇcini element od prva tri u listi ili pak kao srednja vrijednost prva dva elementa. Druga, joˇs bolja ideja je random- izacija algoritma, tj. pivot se izabire kao sluˇcajni element liste. To znatno umanjuje mogu´cnost najgoreg sluˇcaja.

4.3.3 Donja meda sloˇ zenosti algoritama usporedivanja i sor- tiranja temeljenih na usporedivanju

Svi algoritmi opisani do sada u ovom poglavlju temelje se na usporedivanju kao osnovnoj operaciji pomo´cu koje se izvrˇsava premjeˇstanje elemenata u polju. Pri tome smo naˇsli dva algoritma koja imaju sloˇzenost O(n lg n) u

najgorem sluˇcaju, te jedan koji ima sloˇzenost O(n 2 ) u najgorem, ali O(n lg n) u prosjeˇcnom sluˇcaju. Postavlja se pitanje da li se moˇze bolje od toga? U ovom poglavlju bavit ´cemo se ocjenom donje mede maksimalne sloˇzenosti koju neki algoritam sortiranja moˇze imati.

Uvest ´cemo pojam stabla usporedivanja, koja ´ce nam pomo´ci prona´ci donju medu sloˇzenosti naˇsih problema, koje smo ranije obradili, tj. pre- traˇzivanja i sortiranja. Ova stabla ne´cemo definirati formalno, jer se njihova definicija moˇze znatno razlikovati ovisno o problemu koji opisuju.

Stablo usporedivanja za problem pretraˇzivanja definira se na sljede´ci naˇcin: svaki unutarnji vrh stabla predstavljat ´ce usporedbu elementa polja s x, odnosno vrijednoˇs´cu koju traˇzimo. Lijevo podstablo ´ce predstavljati daljnje mogu´cnosti pretraˇzivanja, ako je traˇzeni element manji od proma- tranog elementa polja, a desno podstablo mogu´cnosti daljnjeg pretraˇzivanja ako je traˇzeni element ve´ci od promatranog. Ako je x jednak promatra- nom elementu polja, onda algoritam staje, pa nema podstabla za taj sluˇcaj. Svaki list stabla ´ce predstavljati neuspjeh pretraˇzivanja.

Pogledajmo sada sluˇcaj kada je polje koje se promatra uzlazno sortirano. Osim toga, pretpostavljamo da su elementi u polju medusobno razliˇciti. Za taj sluˇcaj se mogu primijeniti razni algoritmi, od kojih smo dva obradili u prvom dijelu ovog poglavlja. Radi se o slijednom i binarnom pretraˇzivanju.

Slijedno pretraˇzivanje se moˇze malo modificirati kada se radi o sorti- ranom polju. Naime, prvo usporedujemo traˇzeni element s prvim elemen- tom polja. Ako je traˇzeni element manji od prvog u polju, onda je on sigurno manji i od ostalih elemenata polja, pa odmah moˇzemo stati. Za svako usporedivanje koje napravimo moˇzemo dati sliˇcnu argumentaciju, pa algoritam moˇze stati odmah ˇcim u polju naidemo na element koji je ve´ci od traˇzenoga. Stoga slijedno pretraˇzivanje sortiranog polja moˇzemo opisati sljede´cim stablom usporedivanja:

POGLAVLJE 4. ALGORITMI 177

x:A[1]

F x:A[2]

x:A[n-1]

F x:A[n]

Slika 4.7

Vidi se da ovo stablo ima (n + 1) -vu razinu. Dakle, algoritam ´ce u najviˇse n usporedivanja do´ci do rjeˇsenja. Kako svako usporedivanje odnosi najmanje konstantno mnogo vremena, ovaj algoritam ´ce imati vremensku sloˇzenost najgoreg sluˇcaja Ω(n).

S druge strane, binarno pretraˇzivanje sortiranog polja opisano je sljede- ´cim stablom pretraˇzivanja:

x:A[ ⌊ n/2 ⌋ ]

4.3. x:A[ ⌊ n/4 ⌋ ]

x:A[ ⌊ 3n/4 ⌋ ]

V ANJE

x:A[1] ...

x:A[ ⌊ n/2 ⌋ ]

x:A[ ⌊ n/2 ⌋ +1]

x:A[n]

I SOR

F F F F F F F F IRANJE

Slika 4.8

POGLAVLJE 4. ALGORITMI 179 Jasno je da je visina ovog stabla ⌈lg n⌉ + 1. To znaˇci da ´ce binarno

pretraˇzivanje dati odgovor uz najviˇse ⌈lg n⌉ usporedivanja. Dakle, za svaki mogu´ci x vremenska sloˇzenost binarnog pretraˇzivanja bit ´ce Ω(lg n). Sada ´cemo dokazati da je to asimptotski optimalno.

Teorem 4.3 Neka je A polje koje se sastoji od n razliˇcitih vrijednosti, sor- tiranih uzlazno. Minimalna sloˇzenost algoritma za pretraˇzivanje tog polja je Ω(lg n).

Dokaz. Svaki algoritam nad ovim poljem je definiran nekim stablom usporedivanja. Promatrat ´cemo sve listove stabla. Algoritam moˇze neuspjeˇsno zavrˇsiti u bilo kojem elementu stabla. Stoga, svako stablo usporedivanja ovog pro- blema ima toˇcno n listova. Stablo s n listova ima minimalno ⌈lg n⌉ razina.

Broj razina stabla definirat ´ce najve´ci broj koraka koji algoritam mora izvesti da bi izvrˇsio pretraˇzivanje. Uz pretpostavku da se svaki korak moˇze izvesti u konstantnom vremenu, zakljuˇcujemo da algoritam pretraˇzivanja u najgorem sluˇcaju mora imati sloˇzenost Ω(lg n).

Ovaj teorem pokazuje da je binarno pretraˇzivanje asimptotski optimalno pretraˇzivanje sortiranog polja. Promotrimo sada problem sortiranja. I ovdje ´cemo, radi lakˇseg raˇcuna- nja pretpostaviti da su svi elementi polja razliˇciti.

Teorem 4.4 Neka je zadano polje A koje sadrˇzi n razliˇcitih elemenata. Svaki algoritam za sortiranje, temeljen na usporedivanju, ima u najgorem sluˇcaju sloˇzenost Ω(n lg n).

Dokaz. Za problem sortiranja treba se definirati tzv. proˇsireno stablo usporedivanja. Unutarnji ˇcvorovi ovog stabla predstavljaju usporedbe dvaju elemenata polja. Listovi stabla sadrˇze krajnje rjeˇsenje, tj. permutaciju.

Jasno je da listovi moraju pokriti svaku permutaciju ulaznog polja, pa ovo polje ima n! listova. Prema tome, ovo stablo ima ⌈lg n!⌉ razina. Prema Stirlingovoj formuli slijedi da je

Odavde slijedi da algoritam sortiranja, temeljen na usporedivanju, mora u najgorem sluˇcaju imati sloˇzenost Ω(n ln n).

4.3.4 Sortiranje u vremenu O (n) Naslov ovog podpoglavlja na prvi je pogled u suprotnosti rezultatima pret-

hodnog potpoglavlja. Kako je mogu´ce napraviti algoritme koji rade ispod izraˇcunate donje mede? Radi se o tome da smo u prethodnom poglavlju dokazali da algoritmi sortiranja, koji se temelje na usporedivanju, imaju

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE sloˇzenost Ω(n lg n). To znaˇci da moˇzemo na´ci brˇzi algoritam, ali se on

ne moˇze temeljiti na usporedivanju kao osnovnoj operaciji. Je li mogu´ce takvo ˇsto uraditi? Op´cenito nije, ali jest u nekim posebnim sluˇcajevima. U ovom ´cemo poglavlju dati tri algoritma koji su, uz odredene uvjete, brˇzi od O(n lg n).

Sortiranje prebrojavanjem Sortiranje prebrojavanjem je jako jednostavna i efikasna metoda sortiranja,

uz uvjet da je skup S, iz kojeg se uzimaju vrijednosti elemenata, dovoljno mali tako da se moˇze definirati polje veliˇcine |S|. Zbog jednostavnosti, uzet

´cemo da su elementi koje sortiramo cijeli brojevi iz segmenta [1, m]. Neka imamo polje A koje se sastoji od n cijelih brojeva iz segmenta [1, m]. Generira se polje B duljine m, ˇciji se elementi iniciraju na vrijednost

0. Nakon toga se gledaju elementi polja A redom i ako je A[i] = k onda se k-ti element polja B pove´cava za 1. Na kraju tog postupka polje B ´ce sadrˇzavati frekvenciju svakog broja iz segmenta [1, m] u polju A. Nakon toga je joˇs samo potrebno redom puniti polje A elementima ˇciji je broj zapisan u polju B. Formalno, algoritam ´ce izgledati ovako:

Algoritam 4.18 ULAZ: Polje A od n elemenata, ˇcije su vrijednosti cijeli brojevi iz segmenta [1, m]. IZLAZ: Sortirano polje koje se sastoji od elemenata iz polja A.

1. Za i = 1, . . . , m radi B[i] = 0.

2. Za i = 1 . . . , n radi B[A[i]] = B[A[i]] + 1

3. k = 1

4. Za i = 1, . . . , m radi korake 5-7

5. Za j = 1, . . . , B[i] radi korake 6-7

6. A[k] = i

7. k = k + 1 Petlja iz 1 se izvodi m puta, a operacije svakog koraka petlje se izvode

u konstantnom vremenu. Petlja iz 2 izvodi se n puta, a za svaki korak ove petlje potrebno je konstantno vrijeme. Korak 3 je konstantnog trajanja. Korake od 4 do 7 promatrat ´cemo zajedno. Vanjska se petlja izvodi m puta, dok se unutarnja petlja ukupno izvodi onoliko puta koliko ima elemenata polja A, dakle n puta. Stoga se i koraci 6 i 7 izvrˇsavaju n puta. Sloˇzenost ovog algoritma je jednaka za sve ulaze iste duljine i iznosi:

POGLAVLJE 4. ALGORITMI 181

1 +c 2 ·m+c 3 · n. Odnosno,

T CountSearch (n, m) = c

T CountSearch (n, m) = Θ(m + n).

Fiksiramo li m, dobijamo da je

T CountSearch (n) = Θ(n).

Drugim rijeˇcima, ovaj algoritam ´ce sortirati listu u vremenu koje linearno raste s porastom broja elemenata u listi.

Radix sort Ova metoda potjeˇce iz ranijih vremena raˇcunarstva i koristila se kod sorti-

ranja buˇsenih kartica. Metoda se temelji na sortiranju vrijednosti liste prema pojedinim zna- menkama, odnosno prema slovima na pojedinoj poziciji, ako se radi o sor- tiranju alfanumeriˇckih podataka. Zbog jednostavnosti, mi ´cemo ovdje pret- postaviti da se radi o sortiranju cjelobrojnih vrijednosti. U svakom se koraku vrijednosti rasporeduju s obzirom na jednu svoju znamenku, u 10 pomo´cnih polja. No, kako je izvesti? Prva je pomisao da se prvo rasporedivanje izvede po vode´coj znamenci brojeva, pa nakon toga po drugoj, itd. Ovakav pristup zahtjeva vrlo mnogo memorijskog prostora. Naime, u drugom prolazu za

to nam je ve´c potrebno 10 2 = 100 pomo´cnih polja, a u tre´cem 10 3 = 1000 itd. Ovo predstavlja velik utroˇsak memorije. Iako se taj utroˇsak moˇze sma- njiti na dva polja duljine n, svejedno ostaje kˆod, koji je sloˇzen za izvedbu. U ranije doba, kada su se rabile buˇsene kartice, ovakav algoritam ne bi bio pogodan za sortiranje kartica. Koristi se ideja da se prvo rasporedivanje vrˇsi po najmanje znaˇcajnoj znamenci (jedinici). Nakon toga se sve vrijednosti opet upiˇsu u jedno polje, prvo one koje imaju najmanje znaˇcajnu znamenku

0, pa onda one koje imaju najmanje znaˇcajnu znamenku 1, itd. Tako do- biveno polje se sortira po drugoj najmanje znaˇcajnoj znamenci, itd., sve do najznaˇcajnije znamenke. Kada se vrijednosti po posljednji puta spoje u jedno polje, to polje je sortirano. Formalno, ovaj algoritam je:

Algoritam 4.19 ULAZ: Polje A od n elemenata IZLAZ: Sortirano polje koje se sastoji od elemenata iz polja A.

1. Za i := 0, . . . , n radi Index[i] = 0.

2. k := 0.

3. gotovo := T .

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE

4. Za i := 1 . . . , n radi korake 5-8.

5. m := (A[i] ÷ 10 k ) mod 10.

6. Ako je A[i] k ÷ 10 > 0 gotovo := F .

7. Index[m] := Index[m] + 1.

8. B[m, Index[m]] := A[i].

9. Ako je gotovo = T stani.

10. l := 1.

11. Za i := 0, . . . , 10 radi

12. Za j := 1, . . . , Index[i] radi korake 13-14.

13. l := l + 1.

14. A[l] := B[i, j].

15. gotovo := T .

16. k := k + 1.

17. Idi na 4. Kao prvo, ovaj algoritam nije, kao ve´cina ranije opisanih, intuitivno

jasan. Iz njega nije potpuno jasno da on listu sortira ulazno. Stoga je potrebno dokazati da je ovaj algoritam zaista korektan.

Teorem 4.5 (Korektnost) Radix sort algoritam sortira svako zadano po- lje.

Dokaz. Indukcijom po broju znamenaka k, najve´ce vrijednosti u polju. Baza indukcije: Neka k = 1. Ako su svi brojevi jednoznamenkasti, onda ´cemo ih u prvom prolazu podijeliti na 10 pomo´cnih polja. U prvom ´ce biti sve nule, u drugom sve jedinice, itd. Kod spajanja ´ce nule do´ci na poˇcetak, jedinice iza njih itd., pa ´ce polje biti sortirano.

Pretpostavimo da radix sort ispravno sortira brojeve do m znamenaka. Neka je k = m + 1. Nakon m-tog spajanja brojevi ´ce biti sortirani is- pravno po posljednjih m znamenaka. U (m + 1)-om razdijelimo brojeve u

10 pomo´cnih polja, tako da u prvom budu svi koji imaju vode´cu nulu, u drugom svi koji imaju vode´cu jedinicu itd. Osim toga, kako su brojevi bili sortirani po preostalih m znamenaka, u svakom ´ce pomo´cnom polju brojevi biti sortirani. Kada spojimo pomo´cna polja tako da prvo stavimo brojeve s vode´com nulom, pa one s vode´com jedinicom i tako redom, dobit ´cemo sortirano polje.

POGLAVLJE 4. ALGORITMI 183

Pogledajmo sada sloˇzenost ovog algoritma. Neka najve´ci broj u polju ima k znamenaka. Tada ´ce algoritam imati

k prolaza. U svakom prolazu vrijeme potrebno za podjelu vrijednosti po promatranoj znamenci je O(n), i za spajanje takoder O(n). Dakle, imamo

T RadixSort (k, n) = k · (O(n) + O(n)).

Odnosno,

T RadixSort (k, n) = O(k · n).

Ako fiksiramo k, onda ´cemo imati

T RadixSort (n) = O(n).

Ovo vrijedi neovisno o distribuciji, odnosno instanci koju ovaj algoritam sortira. No, valja re´ci da sloˇzenost ovog algoritma znaˇcajno ovisi o veliˇcini brojeva koji se sortiraju.

Sortiranje pomo´ cu pretinaca Tre´ci algoritam sortiranja, sortiranje pomo´cu pretinaca (engl. bucket sort),

nije u najgorem sluˇcaju vremenske sloˇzenosti O(n), ve´c je, u odredenom sluˇcaju prosjeˇcne sloˇzenosti O(n). Taj je sort poznat pod imenom bucket sort

i temelji se na pretpostavci da je distribucija elemenata u polju uniformna na nekom segmentu [m, M ]. Kao ˇsto je ve´c reˇceno, da bi ovaj algoritam radio dobro, elementi polja moraju biti uniformno distribuirani izmedu minimalnog i maksimalnog ele- menta u polju. Ako polje ima n elemenata, stvara se struktura koja ima n pretinaca takvih da u svaki pretinac moˇzemo staviti od 0 do n elemenata. Ovo se moˇze implementirati kao polje ili vezana lista, koja sadrˇzi pokazivaˇce na n vezanih listi ili polja. Ova struktura je poznata kao otvorena hash- tablica, pri ˇcemu je hash-funkcija, koja se ovdje koristi, vrlo jednostavna:

»M−m ¼

h(i) =

+m

U sluˇcaju normalne distribucije oˇcekuje se da ´ce u svakom pretincu hash- tablice biti toˇcno jedan element. Ako ih je viˇse, onda se sortiraju nekom od poznatih standardnih metoda sortiranja. Mi ´cemo koristiti metodu sor- tiranja pomo´cu hrpe iz dva razloga: prvo zato jer ima sloˇzenost O(n · lg n) u najgorem sluˇcaju, pa ´ce i bucket sort naslijediti tu najgoru sloˇzenost i drugo, jer se i tako nakon razmjeˇstanja elemenata u hash-tablicu, elemente iz poje- dinih pretinaca treba proˇcitati i sortirati. Kako bismo odrˇzali ˇcisto´cu bucket sort algoritma, ne ulaze´ci u detalje pomo´cne metode sortiranja, u algoritmu ´cemo kreirati pomo´cno polje i sortirati ga koriste´ci neku od ranije opisanih metoda sortiranja. Kod prepisivanja elemenata odmah ´cemo ih prepisivati

4.3. PRETRA ˇ ZIVANJE I SORTIRANJE u pomo´cnu hrpu. Na taj naˇcin pove´cavamo prostor koji ovaj algoritam za-

htjeva, jer koristimo pomo´cnu strukturu. Moglo bi se pro´ci i bez toga, ako bi se sortiralo izravno u ulaznom polju. No, zato bismo trebali modificirati neki od ranije opisanih algoritama sortiranja. Kada bismo implementirali bucket sort za stvarno koriˇstenje, tada bismo to i uˇcinili, smanjuju´ci time njegovu prostornu, ali i vremensku sloˇzenost. No, na ovoj razini, nama to nije u interesu, jer bi to znatno zakompliciralo naˇse izlaganje, kao i algori- tam koji bismo dobili, i odvelo nas nepotrebno od biti metode u detalje neke druge metode sortiranja.

Stoga imamo sljede´ci algoritam: Algoritam 4.20

ULAZ: Polje A od n elemenata IZLAZ: Sortirano polje koje se sastoji od elemenata iz polja A.

1. Za i := 1, . . . , n radi korak 2.

2. U metni(a[i], h(i)).

3. k := 0.

4. Za i := 1, . . . , n radi korake 5-12.

5. j := 1.

6. Sve dok nije P razan(h(i)) radi korake 7-8.

7. b[j] := Brisi(h(i)).

8. j := j + 1.

9. Ako je j > 1 radi heapsort(b[1], . . . , b[j − 1]).

10. za l := 1, . . . , j − 1 radi korak 11.

11. a[l + k] := b[l].

12. k := k + j − 1. Izraˇcun sloˇzenosti za najbolji i najgori sluˇcaj vrlo je jednostavan. Najgori

je sluˇcaj kada je distribucija vrijednosti elemenata krajnje neuniformna, tj. kada svi elementi osim jednog ulaze u prvi ili posljednji pretinac hash tablice. U tom sluˇcaju imamo sljede´cu sloˇzenost:

T max

BucketSort

(1) + T HeapSort (n − 1). (4.9) Uc 2 ulazi vrijeme potrebno da se izvede jedan korak prve petlje algo-

ritma. Pri tome se pretpostavlja da se umetanje elemenata u hash-tablicu izvodi u konstantnom vremenu.

POGLAVLJE 4. ALGORITMI 185

Petlja iz koraka 4 izvrˇsit ´ce se toˇcno n puta, za svaki pretinac hash-tablice po jednom. Stoga ´ce se koraci 5 i 12, kao i provjera uvjeta iz koraka 9 izvrˇsiti toˇcno n puta, pa ´cemo i njihovo vrijeme dodati u vrijednost konstante c 2 . Petlja iz koraka 6 ´ce se ukupno, u svim koracima petlje iz koraka 4 izvrˇsiti toˇcno n puta, za svaki element ulaznog polja po jednom. Stoga i sva vremena

potrebna za izvrˇsenje jednog njenog koraka, moˇzemo dodati u konstantu c 2 . Sliˇcno je i s petljom iz koraka 10. Preostalo je joˇs samo uvrstiti sloˇzenost koju donosi poziv funkcije heap- sort. Najgore je, kao ˇsto smo ranije rekli, kada se svi elementi osim jednog svrstavaju u jedan pretinac, a to je sluˇcaj koji je opisan u formuli 4.9. To nas dovodi do formule 4.9. Uvrstimo li sloˇzenost sortiranja pomo´cu hrpe imat ´cemo:

T BucketSort

(n) ≤c 1 +n ·c 2 +c 3 +c 4 +c 5 ·n+c 6 · (n − 1) · lg(n − 1). Odnosno,

max

T BucketSort

(n) = O(n · lg n).

max

Minimalna sloˇzenost dobije se ako se pretpostavi u potpunosti uniformna distribucija elemenata. Tada svaki element dolazi u svoj pretinac hash- tablice, pa imamo:

(1), odnosno

T HeapSort

(n) ≤c 1 +n ·c 2 +n ·c 3 = Θ(n). (4.10) Za prosjeˇcnu sloˇzenost treba pretpostaviti uniformnu distribuciju na

T BucketSort

min

veliˇcinu svakog pojedinog elementa, tj. pretpostaviti da je jednako vjero- jatno da ´ce svaki pojedini element u´ci u bilo koji pretinac hash-tablice.

X heapsort T avg

BucketSort

(n) = E Θ(n) +

pri ˇcemu je N i broj elemenata u i-tom pretincu hash tablice. Zbog linear- nosti matematiˇckog oˇcekivanja imamo

X heapsort T avg

X n =n+ heapsort E[T

X heapsort

=n+

T avg

(EN i ).

4.4. ZADACI

Sada joˇs treba izraˇcunati koliko je oˇcekivanje varijable N i . Vjerojatnost da j-ti element padne u i-ti pretinac jest 1 n . Neka je s X ij oznaˇcena indikatorska varijabla vjerojatnosti da je j-ti element u i-tom pretincu.

1 P (X ij = 1) = . n

Sada je

Drugim rijeˇcima, matematiˇcko oˇcekivanje svakog pretinca je da u njemu bude jedan element. Iz toga slijedi da je

T BucketSort

(n) = Θ(n).