34
Sveučilište J. J. Strossmayera u Osijeku Odjel za matematiku Sveučilišni nastavnički studij matematike i informatike Tibor Pejić Sortiranje u linearnom vremenu Diplomski rad Osijek, 2011.

SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Embed Size (px)

Citation preview

Page 1: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Sveučilište J. J. Strossmayera u OsijekuOdjel za matematiku

Sveučilišni nastavnički studij matematike i informatike

Tibor Pejić

Sortiranje u linearnom vremenuDiplomski rad

Osijek, 2011.

Page 2: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Sveučilište J. J. Strossmayera u OsijekuOdjel za matematiku

Sveučilišni nastavnički studij matematike i informatike

Tibor Pejić

Sortiranje u linearnom vremenuDiplomski rad

Mentor: doc. dr. sc. Domagoj Matijević

Osijek, 2011.

Page 3: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Sadržaj

Uvod 1

1 Algoritmi za sortiranje 31.1. Optimalno sortiranje . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.2. Counting sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.3. Radix sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81.4. Bucket sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111.5. Flash sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2 Testiranje algoritama za sortiranje 18

Zaključak 28

Literatura 29

Sažetak 30

Životopis 31

i

Page 4: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Uvod

I prije računala postojali su algoritmi. A, danas kada postoje računala, postoji još višealgoritama i oni se nalaze u srcu računala. No, što su to zapravo algoritmi? Ukratko,algoritam je svaka dobro definirana procedura koja na ulazu prima neki skup vrijed-nosti te na temelju njih proizvodi neki drugi skup vrijednosti na izlazu. Također, sračunalne strane, na algortitam možemo gledati kao na alat za rješavanje određenogračunalnog problema. Na primjer, ako želimo pronaći rješenje sustava linearnih jed-nadžbi, možemo koristiti Gaussovu metodu (algoritam) eliminacije. Ako želimo šifriratidani tekst koristeći određeni ključ, možemo koristiti AES ili neki drugi moderni algo-ritam za šifriranje.

Jedan od fundamentalnih problema u konstrukciji algoritama i programiranju općen-ito jest problem sortiranja. Cilj svakog algoritma za sortiranje jest pronaći permutacijup(1)p(2) . . . p(n) danog niza brojeva 〈a1, a2, . . . , an〉 takvu da je

ap(1) ≤ ap(2) ≤ . . . ≤ ap(n).

Postoji više razloga zašto se sortiranje smatra tako važnim problemom u područjuinformatičkih znanosti:

• Proučavajući različite algoritme za sortiranje možemo dobiti dobar uvid u mnogeelementarne pojmove, važne u analizi i dizajnu algoritama, kao što su asimptotskanotacija, podijeli pa vladaj algoritmi, razilčite strukture podataka itd. Iz tograzloga sortiranje zauzima važno mjesto u mnogim informatičkim udžbenicima.

• Ponekad okolnosti u primjeni zahtijevaju sortiranje. Zamislimo samo rječnik ukojemu riječi nisu poredane leksikografski.

• Pretraživanje sortirane liste je znatno brže, nego pretaživanje nesortirane listepodataka.

• Mnogi složeniji algoritmi se koriste sortiranjem. Primjerice, program koji obrađujegrafičke objekte koji su postavljeni jedan iznad drugog prvo treba sortirati objekteprema relaciji iznad, a tek onda nacrtati sve objekte po redu.

Također, o važnosti algoritama za sortiranje govori i činjenica da mnogi programi zaispitivanje performansi računalnog hardwarea koriste sortiranje kao jedan od testovakoje provode.

1

Page 5: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Kao posljedica toga razvijen je velik broj različitih algoritama za sortiranje, od onihjednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja odgovaraΘ(n2), do onih složenijih kao što su merge sort i heap sort, čije je vrijeme izvršenjajednako Θ(n lg n). Postoje čak i algoritmi koji su izmišljeni kao informatičke šale,primjerice bogo sort s prosječnim vremenom izvršenja O(n ·n!). No, tema ovog rada sualgoritmi koji, uz određene, dodatne, pretpostavke, imaju linearno vrijeme izvršenja ikoji, kako ćemo kasnije vidjeti, čine, asimptotski gledano, klasu najbržih algoritama zasortiranje.

U poglavlju 1 je dat kratak opis najvažnijih metoda koje koriste algoritmi za sorti-ranje, a zatim je u prvom dijelu razmatrano pitanje optimalne složenosti algoritama zasortiranje. Ostatak poglavlja je posvećen teorijskom razmatranju algoritama countingsort, radix sort, bucket sort i flash sort koji pod određenim uvjetima imaju linearnovrijeme izvršenja. Poglavlje 2 je zapravo eksperimentalni dio rada, u kojemu su testi-rane C++ implementacije algoritama razmatranih u poglavlju 1 te su njihova vremenaizvršenja uspoređena sa STL funkcijom sort().

2

Page 6: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Poglavlje 1

Algoritmi za sortiranje

Već smo prije vidjeli da postoje različiti algoritmi za sortiranje. Prema tehnici kojom sekoriste svi algoritmi za sortiranje se ugrubo mogu podijeliti u sljedećih osam skupina:

1. Insertion. Elemente niza promatramo jedan po jedan te svaki novi elementumećemo na odgovarajuće mjesto u odnosu na već sortirani dio niza. Ovo jenačin na koji većina igrača slaže karte. Prirodno, najvažnije predstavnik oveskupine algoritama je insertion sort.

2. Exchange. Ako pronađemo dva elementa koja nisu u odgovarajućem redosljedu(jedan u odnosu na drugi), onda ih zamjenimo i taj postupak ponavljamo svedok ni jedna zamjena više nije potrebna. Najpoznatiji predstavnici ove metodesortiranja su bubble sort i quick sort.

3. Selection. Prvo pronađemo najmanji element te ga nekako odvojimo od ostalih,zatim sljedeći najmanji itd. Ovom tehnikom se koriste selection sort i heap sort.

4. Merging. Ideja ove tehnike leži u spajanju dvaju prethodno sortiranih podnizovau jedan novi sortirani niz. Najvažniji algoritam koji koristi ovu metodu jest mergesort.

5. Enumeration. Sekvencijalno prolazeći kroz niz za svaki element prebrojavamokoliko ima elemenata koji su manji te koristeći to znanje određujemo konačnupoziciju svakog od elemenata. Primjer algoritma koji koristi ovu tehniku jestcounting sort.

6. Distribution. Ideja algoritama koji koriste ovu metodu je upravo suprotnaonima iz skupine 4. Ovdje se početni niz dijeli u više manjih podnizova takoda su svi elementi podniza 1 manji od svakog od elemenata podniza 2. U ovuskupinu pripadaju bucket sort, flash sort i radix sort.

7. Luck. Nasumice mješamo elemente niza, sve dok ne dobijemo sortirani niz. Ovoje očito vrlo neučinkovita metoda, uzimajući u obzir građu današnjh računala.

3

Page 7: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

S druge strane, ova metoda je vrlo zanimljiva za implementaciju na kvantnimračunalima. Predstavnik ove metode je već spomenuti bogo sort.

8. Special. U ovu skupinu pripadaju svi algoritmi koji zahtijevaju vrlo specijalneulazne podatke ili pak zahtijevaju poseban hardware. Primjeri takvih algoritamasu pancake sort, spaghetti sort i mrežno sortiranje.

Dakako, postoje i hibridni algoritmi, odnosno, oni koji koriste više od jedne od nave-denih tehnika i upravo se takvi algoritmi najviše koriste u praksi.

Osim navedenih tehnika sortiranja postoji još jedno svojstvo koje će nam biti zan-imljivo u daljnjoj raspravi, a to je stabilnost.

Definicija 1.1. Kažemo da je algoritam za sortiranje stabilan ako se brojevi s jednakomvrijednosti u izlaznom nizu pojavljuju u istom redosljedu kao i u ulaznom nizu.

0 1 2 3 4 0 1 2 3 4A (5,1) (8,9) (3,2) (3,4) (8,7) A (5,1) (8,9) (3,2) (3,4) (8,7)

0 1 2 3 4 0 1 2 3 4B (3,2) (3,4) (5,1) (8,9) (8,7) B (3,4) (3,2) (5,1) (8,7) (8,9)

(a) (b)

Slika 1.1: Primjer stabilnog (a) i nestabilnog (b) sortiranja (po prvome elementu) nizadvodimenzionalnih vektora. U ulaznom nizu A element (3,2) se nalazi ispred elementa (3,4).Stabilno sortiranje pod (a) zadržava njihov relativni poredak, dok je u slučaju nestabilnogsortiranja pod (b) njihov poredak zamijenjen.

Ovo svojstvo je važno kada uz elemente koje sortiramo postoje i satelitski podacikako je to slučaj na slici 1.1. Prvi element dvodimenzionalnog vektora je vrijednost pokojoj sortiramo, a sve ostalo su satelitski podaci.

1.1. Optimalno sortiranjePored same tehnike koju koristi neki algoritam ono što nas najviše zanima jest njegovovrijeme izvršenja. Proučavajući tako različite algoritme za sortiranje nameće nam sepitanje: Koliko brzo uopće možemo sortirati? No, prije neko što odgovorimo na topitanje, proučimo jedan poseban model sortiranja, sortiranje uspoređivanjem (compar-ison sort). Jedina operacija koja je dozvoljena u ovom modelu, osim, naravno, promjeneredosljeda elemenata, jest njihovo uspoređivanje koristeći relaciju ” ≤ ”. Ovaj modelizgleda prilično ograničavajuće, ali je veoma važan jer ga koriste, kako algoritmi iz prvečetiri skupine iz prethodnog poglavlja, tako i najčešće korišteni algoritmi ugrađeni u

4

Page 8: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Slika 1.2: Primjer stabla odluke za niz 〈5, 9, 2〉. i : j označava uspoređivanje elemenata ai

i aj . Listovi označeni pravokutnicima označavaju konačne permutacije 〈p(1), p(2), p(3)〉. Os-jenčani put naznačuje tijek donesenih odluka prilikom sortiranja. Postoji 3! = 6 permutacijaelemenata ulaznog niza pa stablo odluke mora imati najmanje 6 listova.

našim računalima. Odgovorimo, onda, na pitanje: Koliko brzo možemo sortirati us-poređivanjem?

Definicija 1.2. Puno binarno stablo je stablo kod kojeg svi čvorovi, osim listova, imajutočno dva djeteta.

Da bismo odgovorili na to pitanje, promotrimo model stabla odluke (puno binarnostablo). Na slici 1.2 je dan primjer takvog stabla odluke, pomoću kojega možemosortirati nizove od 3 elementa. Svaki unutarnji čvor označava jedno uspoređivanjeai ≤ aj. Lijevo podstablo označava slučaj kad je ai ≤ aj, a desno podstablo slučaj kadaje ai > aj. Kada dođemo do lista u stablu odluke, došli smo do konačne permutacijekoja nam daje sortirani niz.

Promotrimo sada vezu između modela stabla odluke i sortiranja uspoređivanjemza ulazni niz od n elemenata. Primijetimo da svakome sortiranju uspoređivanjemodgovara jedno stablo odluke (ili više njih ako se radi o randomiziranome algoritmu),za svaku moguću vrijednost broja n. Svaki puta kad radimo uspoređivanje, algoritammože krenuti u jednom od dva smjera, koji, u slučaju stabla odluke, odgovaraju lijevomi desnom podstablu. Takvo stablo odluke koje odgovara sortiranju uspoređivanjem,sadrži redoslijed uspoređivanja za sve moguće permutacije ulaznog niza. Da bi takvostablo odluke bilo u stanju sortirati svaki niz od n elemenata, mora biti u stanju doćido svake od n! permutacija toga niza, što znači da broj listova u tome stablu mora bitinajmanje n!.

Vrijeme izvršenja (broj uspoređivanja) je jednako duljini puta od korijena do listašto je u najgorem slučaju jednako visini stabla. Dakle, donja granica visine svih stabalaodluke u kojima se sve permutacije pojavljuju kao listovi jest ujedno donja granicavremena izvršenja za sve algoritme temeljene na uspoređivanju.

5

Page 9: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Teorem 1.1. Svaki algoritam sortiranja uspoređivanjem zahtjeva Ω(n lg n) uspoređi-vanja u najgorem slučaju.

Dokaz. Iz prethodne rasprave znamo da je dovoljno odrediti visinu stabla odluke.Promotrimo stablo odluke visine h s l listova. Da bi stablo odluke bilo u stanju datikorektan rezultat za svaku permutaciju ulaznog niza, svaka od n! permutacija se morapojaviti na nekome od listova, što znači da je n! ≤ l. S druge strane znamo da binarnostablo visine h ima najviše 2h listova. Slijedi da je

n! ≤ l ≤ 2h,

odakle logaritmiranjem dobivamo

h ≥ lg (n!).

A, kako prema Stirlingovoj aproksimaciji vrijedi

lg (n!) = n lg n− n

ln 2 + 12 lg n+O(1),

slijedi da je h = Ω(n lg n).

Dakle, sada smo odgovorili koliko brzo možemo sortirati uspoređivanjem. Na pi-tanje koliko brzo uopće možemo sortirati lako je dati odgovor. Da bismo znali na kojemjesto moramo staviti svaki od n elemenata niza, očito ih moramo sve pregledati paje donja granica vremena izvršenja za bilo koji algoritam sortiranja jednaka Ω(n). Usljedećim poglavljima ćemo vidjeti nekoliko algoritama koji postižu tu granicu.

1.2. Counting sortCounting sort pretpostavlja da je svaki od n elemenata ulaznog niza cijeli broj iz skupa0, 1, 2, . . . , k, za neki cijeli broj k. Kada je k = O(n), izvršno vrijeme odgovara Θ(n).

Counting sort za svaki element x određuje broj elemenata manjih od x te koristećitu informaciju stavlja x na pravo mjesto u izlaznom nizu. Na primjer, ako je 11elemenata manje od x, onda se x treba postaviti na 12. mjesto. Naravno, ovakvaprocedura funkcionira samo ako su svi elementi međusobno različiti. No, vidjet ćemoda se uz male modifikacije može prilagoditi tako da radi i u općem slučaju.

U pseudokodu za counting sort pretpostavljamo da je ulazni niz A[1..n], te jelength(A) = n. Osim toga koristimo dva dodatna niza: B[1..n], kao izlazni niz, iC[0..k], koji će sadržavati informacije o tome na koje mjesto treba staviti pojedini ele-ment.

6

Page 10: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Slika 1.3: Rad procedure Counting-Sort na ulaznom nizu A[1..8], gdje je svaki elementod A nenegativni cijeli broj ne veći od k = 5. (a) Niz A i pomoćni niz C nakon linije 5. (b)Niz C nakon linije 8. (c)-(e) Izlazni niz B i niz C nakon jedne, dvije i tri iteracije petlje ulinijama 10-12. Tamno osjenčani dijelovi niza B nisu popunjeni. (f) Konačni izgled niza B

nakon sortiranja.

Counting-Sort(A,B, k)1 neka je C[0..k] novi niz (polje)2 for i = 0 to k3 C[i] = 04 for j = 1 to length(A)5 C[A[j]] = C[A[j]] + 16 //C[i] sad sadrži broj elemenata jedankih i.7 for i = 1 to k8 C[i] = C[i] + C[i− 1]9 //C[i] sad sadrži broj elemenata manjih ili jednakih i.10 for j = length(A) downto 111 B[C[A[j]]] = A[j]12 C[A[j]] = C[A[j]]− 1

Slika 1.3 ilustrira rad counting sorta. Nakon što for petlja u linijama 2-3 postavisve elemente niza C na 0, for petlja u linijama 4-5 prolazi kroz sve elemente ulaznogniza te ako je vrijednost elementa jednaka i, inkrementiramo C[i]. Dakle, nakon linije5, C[i] sadrži broj elemenata jednakih i, za sve i = 0, 1, . . . , k. Linije 7-8 određujukoliko je elemenata manjih ili jednakih i, za svaki i = 0, 1, . . . , k. Konačno, for petlja ulinijama 10-12 stavlja svaki element A[j] na točno mjesto u izlaznom nizu B.

Ako su svi od n elemenata različiti, tada za svaki A[j], vrijednost C[A[j]] sadržitočnu konačnu poziciju elementa A[j], jer postoji točno C[A[j]] elemenata manjih ilijednakih A[j]. Kako nisu svi elementi nužno različiti, vrijednost C[A[j]] smanjujemoza jedan svaki puta kad stavimo element A[j] u B. Dekrementacija C[A[j]] znači da ćesljedeći element s vrijednosti jednakom onoj od A[j], ako postoji, biti postavljen točno

7

Page 11: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

jedno mjesto prije A[j] u izlaznom nizu.Analizirajmo sada izvršno vrijeme counting sorta. For petlja u linijama 2-3 Θ(k)

vremena, for petlja u linijama 4-5 zahtijeva Θ(n) vremena, for petlja u linijama 7-8zahtijeva Θ(k), a petlja u linijama 10-12 zahtijeva Θ(n) vremena. Stoga je ukupnovrijeme izvršenja Θ(k + n). U praksi, counting sort obično koristimo kad je k = O(n)te je tada vrijeme izvršenja zapravo Θ(n).

No, pogledajmo sada koliko dodatne memorije koristi counting sort. Prvo imamoizlazni niz B koji će sadržavati sortirani niz te kao takav zahtijeva Θ(n) memorije.Zatim, već u prvoj liniji imamo niz C[1..k] koji očito koristi Θ(k) memorije. Osimnizova B i C imamo još brojače (cijele brojeve) i i j čija veličina ne ovisi o ulaznomnizu A te koriste Θ(1) memorije. Dakle, ukupna memorija koju koristi counting sort,osim one za samu pohranu ulaznog niza A, je jednaka Θ(n + k). Ako pretpostavimoda je k = O(n), onda dodatna memorija koju koristi counting sort odgovara Θ(n).

Kako counting sort ne sortira uspoređivanjem, on može biti (i jest) brži od donjegranice Ω(n lg n) dokazane u poglavlju 1.1. Štoviše, u cijelom kodu counting sorta nepostoji ni jedno uspoređivanje. Umjesto toga, counting sort koristi vrijednosti eleme-nata da bi odredio njihovo konačno mjesto u nizu. Odavde možemo vidjeti da donjagranica od Ω(n lg n) ne vrijedi ako se udaljimo od modela sortiranja uspoređivanjem.S druge strane, valja primijetiti da counting sort koristi Θ(n+ k) dodatne memorije, uodnosu na, primjerice, quick sort koji radi u mjestu.

Iz posljednje for petlje u linijama 10-12 lako se vidi da je counting sort stabilan.Osim što je ovo svojstvo važno kod sortiranja složenijih nizova (onih gdje elementisadrže satelitske podatke), stabilnost counting sorta nam je važna iz još jednog razloga:counting sort se često koristi kao potprogram unutar radix sorta. A, kao što ćemovidjeti u sljedećem poglavlju, da bi radix sort radio pravilno, counting sort mora bitistabilan.

1.3. Radix sortRadix sort je algoritam koji su koristili strojevi za sortiranje bušenih kartica, kakvedanas možemo vidjeti samo u tehničkim muzejima. Kartice imaju 80 stupaca te 12mjesta u svakom stupcu na kojemu može biti probušena rupa. Mašina za sortiranje jemehanički programirana da pregleda određeni stupac i rasporedi kartice u 12 odjeljaka,ovisno o tome na kojem mjestu je kartica probušena. Nakon toga bi operater prikupiokartice iz svih odjeljaka te ih redom složio tako da su na vrhu one kartice koje imajuprobušeno prvo mjesto u datom stupcu, zatim one koje imaju probušeno drugo mjestoitd.

Za decimalne brojeve, svaki stupac bi trebao sadržavati 10 mjesta, a broj s d zname-naka bi trebao d stupaca. Kako stroj za sortiranje može pregledati samo jedan stupacodjednom, da bismo sortirali n kartica koje sadrže d-znamenkaste brojeve, potreban

8

Page 12: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

nam je algoritam za sortiranje.Intuitivno, mogli bismo početi sortirati po najznačajnijoj znamenci te svaki odjeljak

sortirati rekurzivno, a zatim posložiti redom sve kartice počevši s odjeljkom 1, zatimodjeljkom 2 itd. Upravo opisana metoda se naziva MSD-radix sort (MSD = mostsignificant digit). Problem koji se javlja kod te metode jest veliki broj potrebnihodjeljaka. Na primjer, da bismo sortirali naše kartice s početka priče, u najgoremslučaju bi nam bilo potrebno 1280 različitih odjeljaka.

Metoda koja će nas više zanimati u ovome radu jest LSD-radix sort (LSD = leastsignificant digit), koju ćemo nadalje zvati jednostavno radix sort. Prema [3], prvaobjavljena referenca na ovaj princip sortiranja se pojavljuje u raspravi L. J. Comriea oopremi za bušene kartice [Transactions of Office Machinery Users’ Assoc., Ltd. (1929),25-37, esp. p. 28]. Ovaj algoritam je vrlo sličan prethodno opisanom MSD-radix sortu.Razlika je u tome što se prvo sortira po posljednjoj, najmanje značajnoj, znamenci,zatim po pretposljednjoj itd. No, umjesto da se svaki odjeljak sortira rekurzivno, nakonsortiranja po jednoj znamenci kartice se redom prikupljaju u jedan špil i sortiranjepočinje ponovo po sljedećoj znamenci.

Da bi ova metoda pravilno radila, algoritam koji sortira prema znamenkama morabiti stabilan i operater koji prikuplja kartice iz odjeljaka ne smije mjenjati njihovredosljed čak ni ako se sve nalaze u istom odjeljku.

Slika 1.4: Primjer rada radix sorta na nizu od 7 troznamenkastih brojeva. Prvi stupac lijevo jeulazni niz. Ostali stupci prikazuju iteracije sortiranja po znamenkama sve veće značajnosti. Sjenčanjeoznačava znamenku po kojoj se sortira.

Pseudokod radix sorta je prilično jednostavan. Sljedeća procedura pretpostavlja dasvaki od n elementa niza A ima d znamenaka, gdje je 1 najmanje značajna, a d, pak,najznačajnija znamenka.

Radix-Sort(A, d)1 for i = 1 to d2 koristeći stabilan algoritam za sortiranje sortiraj niz A po znamenci i

Da u liniji 2 nismo zahtijevali stabilnost algoritma koji sortira po i-toj znamenci,moglo bi se dogoditi da po završetku rada radix sorta niz A ne bude pravilno sortiran,što je ilustrirano na slici 1.5. Do toga dolazi jer nestabilan algoritam ne zadržavarelativni poredak elemenata s jednakim vrijednostima te sortiranjem po znamenci veće

9

Page 13: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

značajnosti može pokvariti redoslije dobiven sortiranjem po manje značajnoj znamenci.

Slika 1.5: Primjer rada radix sorta koji koristi nestabilni algoritam za sortiranje po i-toj znamenci.Zbog nestabilnosti u drugom stupcu su zamjenjeni brojevi 720 i 329. Slično, u trećem stupcu jepromjenjen redoslijed brojeva 355 i 329 te 457 i 436, što rezultira nepravilno sortiranim nizom.

Propozicija 1.1. Neka je dano n d-znamenkastih brojeva i neka svaka znamenka možepoprimiti jednu od najviše k mogućih vrijednosti. Tada Radix-Sort sortira te brojeveu Θ(d(n+ k)) vremenu, ako stabilni algoritam koji koristi zahtijeva Θ(n+ k) vremena.

Dokaz. Točnost radix sorta se lako dokazuje indukcijom po broju znamenaka. Vri-jeme izvršenja ovisi o stabilnom algoritmu za sortiranje koji se koristi. Kada je svakaznamenka iz skupa 0, 1, 2, . . . , k− 1, uz pretpostavku da k nije suviše velik, countingsort se nameće kao očiti izbor. Svaki prolaz kroz n d-znamenkastih brojeva onda zahti-jeva Θ(n+ k) vremena, a kako se taj postupak mora ponoviti d puta, ukupno vrijemeizvršenja radix sorta jest Θ(d(n+ k)).

Dakle, kad je d konstanta i k = O(n), radix sort radi u linearnom vremenu. Općen-ito, ovisno o računalnom zapisu, broj možemo razbiti na različite načine na znamenke.

Propozicija 1.2. Neka je dano n b-bitnih brojeva te neki pozitivan cijeli broj r ≤ b.

Radix-Sort sortira te brojeve u Θ((b/r)(n+2r)) vremenu. Uz pretpostavku da stabilanalgoritam za sortiranje koji se koristi zahtijeva Θ(n+k) vremena, za elemente iz skupa0, 1, 2, . . . , k.

Dokaz. Za svaki r ≤ b, na broj gledamo kao da ima d = db/re znamenaka od r

bitova. Svaka znamenka je cijeli broj iz skupa 0, 1, . . . , 2r − 1, tako da možemokoristiti counting sort za k = 2r − 1. Na primjer, na 32-bitnu riječ možemo gledatikao da ima četiri 8-bitne znamenke, tako da je b = 32, r = 8, k = 2r − 1 = 255 id = b/r = 4. Svaki prolaz counting sorta nas košta Θ(n+k) = Θ(n+2r), a kako imamod prolaza, ukupno vrijeme izvršenja je Θ(d(n+ 2r)) = Θ((b/r)(n+ 2r)).

Pokušajmo sada, za dane n i b, odrediti takav r ≤ b da je izraz (b/r)(n + 2r)minimalan. Ako je b ≤ blg nc, tada je za bilo koji r ≤ b, n+2r = Θ(n). Stoga, uzimajućir = b dobivamo da je vrijeme izvršenja (b/b)(n + 2b) = Θ(n), što je asimptotskioptimalno. Ako je b ≥ blg nc uzimajući r = blg nc, dobivamo asimptotski gledano

10

Page 14: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

najbolje vrijeme od Θ(bn/ lg n). Kada bismo povećali r iznad blg nc, tada bi izraz 2r

u brojniku brže rastao nego izraz r u nazivniku te bismo tako dobili izvršno vrijemeiznad Ω(bn/ lg n). Kad bismo, s druge strane, smanjili r ispod blg nc, tada bi izraz b/rrastao, dok bi izraz n+ 2r ostao jednak Θ(n).

Je li radix sort zaista, u praksi, brži od algoritama za sortiranje baziranih na us-poređivanju, kao što je primjerice quick sort? Ako je b = O(lg n), što je često slučaj,i ako odaberemo r ≈ lg n, tada je izvršno vrijeme radix sorta Θ(n), što je bolje odočekivanog vremena izvršenja quick sorta od Θ(n lg n). No, konstantni faktori skriveniasimptotskom notacijom se razlikuju. U poglavlju 2 ćemo vidjeti da je za velike n radixsort zaista brži.

Ono na što, također, treba obratiti pažnju jest činjenica da verzija radix sorta kojakoristi counting sort za stabilno sortiranje, ne sortira u mjestu, već koristi Θ(n + 2r)dodatne memorije. Dakle, kada je opterećenje memorije na vrhuncu, možda bi bilobolje koristiti algoritam koji radi u mjestu, kao što je quick sort. Osim toga, trebaprimijetiti da se LSD-radix sort ne može u potpunosti paralelizirati (jer se sortiranjapo znamenkama, koja obavlja counting sort, moraju odvijati sekvencijalno) za razlikuod, primjerice, quick sorta ili merge sorta.

1.4. Bucket sortBucket sort pretpostavlja da su ulazni podaci iz uniformne distribucije i ima očekivanovrijeme izvršenja jednako Θ(n).Kao i counting , bucket sort je brz jer prtpostavlja neštoo ulaznom nizu. Dok counting sort pretpostavlja da su ulazni podaci cijeli brojevi izskupa 0, 1, 2, . . . , k, gdje je k relativno malen, bucket sort pretpostavlja da su ulaznipodaci dobiveni slučajnim procesom koji distribuira elemente uniformno i nezavisno naintervalu [0, 1).

Bucket sort dijeli interval [0, 1) na n podintervala (bucket) jednake duljine te ras-poređuje n ulaznih brojeva u te podintervale. Kako su podaci uniformno raspoređeni naintervalu [0, 1), očekujemo da će se u svakom podintervalu nalaziti podjednako malenbroj elemenata. Da bismo dobili izlazni niz, jednostavno sortiramo elemente u svakomod podintervala te redom spojimo sve podintervale.

U pseudokodu za bucket sort pretpostavljamo da je A ulazni niz od n elemenatate da svaki element A[i] zadovoljava 0 ≤ A[i] < 1. Potreban nam je dodatni nizB[0, . . . , n− 1] vezanih listi (bucket), uz pretpostavku da postoji mehanizam za održa-vanje takvih listi.

11

Page 15: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Slika 1.6: Procedura bucket sort za n = 10. (a) Ulazni niz A[1..10]. (b) Niz B[0..9] sortiranih listi(bucket) nakon izvršenja linije 8. Lista i vrijednosti iz intervala [1/10, (i + 1)/10). Sortirani izlazni nizje sastavljen od redom spojenih listi B[0], B[1], . . . , B[9].

Bucket-Sort(A)1 n= length(A)2 neka je B[0, . . . , n− 1] novi niz (polje)3 for i = 0 to n− 14 neka je B[i] prazna lista5 for i = 1 to n6 umetni A[i] u listu B[bnA[i]c]7 for i = 0 to n− 18 sortiraj listu B[i] insertion sortom9 redom spoji liste B[0], B[1], . . . , B[n− 1]

Slika 1.6 prikazuje rad procedure bucket sort na nizu od 10 brojeva.Da bismo se uvjerili da algoritam zaista radi, promotrimo dva elementa A[i] i A[j].

Bez smanjenja općenitosti pretpostavimo da je A[i] ≤ A[j]. Kako je bnA[i]c ≤ bnA[j]c,element A[i] ide ili u istu listu kao i A[j] ili u listu s manjim indeksom. Ako se A[i] iA[j] nalaze u istoj listi, onda ih for petlja u linijama 7-8 stavlja u pravilan redosljed.Ako se A[i] i A[j] nalaze u različitim listama, tada i linija 9 stavlja u pravilan redosljed.Dakle, bucket sort radi pravilno.

Prijeđimo, sada, na analizu izvršnog vremena bucket sorta. Primijetimo da sve linijeosim linije 8 zahtijevaju O(n) vremena u najgorem slučaju. Dakle, trebamo analiziratiukupno vrijeme potrebno za n poziva insertion sorta u liniji 8.

U svrhu analize poziva insertion sorta, neka je ni slučajna varijabla kojom modeli-ramo broj elemenata u listi B[i]. Kako insertion sort ima kvadratno vrijeme izvršenja,vrijedi da je izvršno vrijeme bucket sorta jednako

T (n) = Θ(n) +n−1∑i=0

O(n2i ).

12

Page 16: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Odredimo, sada, očekivano vrijeme izvršenja bucket sorta. Uzimajući očekivanje naobje strane te koristaći linearnost očekivanja, imamo

E[T (n)] = E[Θ(n) +

n−1∑i=0

O(n2i )]

= Θ(n) +n−1∑i=0

E[O(n2i )]

= Θ(n) +n−1∑i=0

O(E[n2i ]). (1.1)

Tvrdimo da jeE[n2

i ] = 2− 1n, i = 0, 1, . . . , n− 1. (1.2)

Svaka lista i ima istu vrijednost E[n2i ], jer svaki element ulaznog niza A s jednakom

vjerojatnošću upada u bilo koju od listi. Da bismo dokazali jenadžbu (1.2), definirajmoindikator slučajnu varijablu

Xij = IA[j] upada u listu i, i = 0, 1, . . . , n− 1, j = 1, 2, . . . , n.

Odakle slijedi da jeni =

n∑j=1

Xij.

Izračunajmo, sada, E[n2i ].

E[n2i ] = E

n∑

j=0Xij

2

= E

n∑j=1

n∑k=1

XijXik

= E

n∑j=1

X2ij +

∑1≤j≤n

∑1≤k≤n

k 6=j

XijXik

=

n∑j=1

E[X2ij] +

∑1≤j≤n

∑1≤k≤n

k 6=j

E[XijXik] (1.3)

Promotrimo dvije sume posebno. Kako je indikator slučajna varijabla jednaka 1 svjerojatnošću 1/n i 0 inače, slijedi da je

E[X2ij] = 12 · 1

n+ 02 ·

(1− 1

n

)= 1n.

Kada je k 6= j, varijable Xij i Xik su nezavisne te je

E[XijXik] = E[Xij]E[Xik] = 1n· 1n

= 1n2 .

13

Page 17: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Supstituirajući te vrijednosti nazad u jednadžbu (1.3), dobivamo

E[n2i ] =

n∑j=1

1n

+∑

1≤j≤n

∑1≤k≤n

k 6=j

1n2

= n · 1n

+ n(n− 1) · 1n2

= 1 + n− 1n

= 2− 1n,

čime je jednadžba (1.2) dokazana.Koristeći tu činjenicu u jednadžbi (1.1), možemo zaključiti da je očekivano vrijeme

izvršenja bucket sorta jednako Θ(n) + n ·O(2− 1/n) = Θ(n).Iz prethodne rasprave možemo zaključiti da pretpostavka o uniformnoj distribu-

ciji nije nužna, da bi izvršno vrijeme bucket sorta bilo linearno. Dovoljno je da sumakvadrata broja elemenata u listama B[i] bude linearna u odnosu na ukupan broj el-emenata ulaznog niza, a za to je dovoljno da vjerojatnosti da slučajno izabrani el-ement upadne u bilo koju od listi budu međusobno jednake, tj. Xij = 1/n, i =0, 1, . . . , n− 1, j = 1, 2, . . . , n.

Dakle, da bi očekivano vrijeme izvršenja bucket sorta bilo linearno, dovoljno jepoznavati distribuciju (funkciju distribucije) iz koje dolaze ulazni podaci te prematome odrediti granice podintervala tako da se u svakoj listi B[i] nalazi približno jednakbroj elemenata ulaznog niza A.

Primijetimo još da bucket sort koristi dodatni niz B, što znači da zahtijeva Θ(n)dodatne memorije. Najveća prednost bucket sorta, u odnosu na druge algoritme zasortiranje u linearnom vremenu, leži u činjenici da se bucket sort može lako i prirodnoparalelizirati.

1.5. Flash sortFlash sort, kao i bucket sort, pretpostavlja da podaci dolaze iz uniformne distribucijete mu je očekivano vrijeme izvršenja jednako Θ(n). Ono što flash sort razlikuje odbucket sorta jest činjenica da flash sort obavlja sortiranje u mjestu.

Umjesto da elemente početnog niza A stavlja u novi niz B, kako to radi bucket sort,flash sort koristi samo dodatni niz L[0, . . . ,m − 1] kako bi odredio koliko elemenatatreba staviti u svaku od m klasa, a zatim premještajući elemente unutar niza A stavljaodgovarajuće elemente u pripadne klase.

Niz L dobivamo slično kao niz C u counting sortu, samo što umjesto doslovnogprebrojavanja elemenata, prebrojavamo koliko elemenata pripada svakoj od m klasa,tako da na kraju L[i] sadrži ukupan broj elemenata u svim klasama od 0 do i. Nakontoga krećemo s permutacijama (premještanjima) elemenata unutar početnog niza A,

14

Page 18: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

koje se odvijaju na sljedeći način. Uzmemo element A[i], odredimo klasu k kojoj tajelement pripada te A[i] stavimo na mjesto L[k] (prvo nepopunjeno mjesto u klasi k),a element koji se prije nalazio na tom mjestu pamtimo, jer ćemo permutacije nastavitiupravo s tim elementom. Zatim L[k] smanjujemo za jedan jer smo popunili jednomjesto u klasi k.

Može se dogoditi da tako premještajući elemente završimo na onom mjestu s kojegsmo krenuli i prije nego što smo sve elemente stavili u pripadne klase. To znači daje završio jedan ciklus permutacija te je potrebno pronaći element s kojim možemozapočeti sljedeći ciklus. Za početak ciklusa jednostavno odabiremo prvi element kojise ne nalazi u odgovarajućoj klasi. Sve pemutacije se završavaju nakon n− 1 izvršenihpremještanja elemenata, jer ako smo n − 1 elemenata stavili u odgovarajuće klase, toznači da se i n-ti element nalazi u odgovarajućoj klasi.

U pseudokodu za flash sort pretpostavljamo da je A ulazni niz od n elemenata teda svaki element A[i] zadovoljava 0 ≤ A[i] < 1. Također nam je potreban pomoćni nizL[0, . . . ,m− 1].

Flash-Sort(A)1 n = length(A)2 neka je L[0, . . . ,m− 1] novi niz (polje)3 for i = 0 to m− 14 L[i] = 05 for i = 1 to n6 L[bmA[i]c] = L[bmA[i]c] + 17 //L[i] sad sadrži broj elemenata u klasi i8 for i = 1 to m− 19 L[i] = L[i] + L[i− 1]10 //L[i] sad sadrži broj elemenata u svim klasama ≤ i, odnosno gornju granicu klase i11 hold =max(A), A[1] = hold, nmove = 0, i = 0, k = m− 112 //nmove = broj izvršenih premutacija, k = klasa trenutno promatranog elementa13 while nmove ≤ n− 114 while i > L[k]− 115 i = i+ 116 k = bmA[i]c17 flash = A[i]18 while i 6= L[k]19 k = bm · flashc20 hold = A[L[k]]21 A[L[k]] = flash22 flash = hold23 L[k] = L[k]− 124 nmove = nmove+ 125 sortiraj niz A insertion sortom

Slika 1.7 prikazuje odvijanje zamjena u mjestu na nizu od 7 elemenata u slučajukad se konačna permutacija sastoji od jednog (a) odnosno dva ciklusa (b).

15

Page 19: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Slika 1.7: Primjer rada flash sorta za n = 7 i m = 7. (a) Permutacije u mjestu se odvijaju u jednomciklusu. (b) Permutacije se odvijaju u dva ciklusa.

Petlja while u linijama 13-24 osigurava da ukupni broj premještanja elemenata nebude veći od n, jer je to dovoljno da bi se svi elementi posložili u odgovarajuće klase.Petlja while u linijama 18-24 stavlja element flash u odgovarajuću klasu u slučaju dapostoje slobodna mjesta u toj klasi, u protivnom, znači da je trenutni ciklus je završiote while petlja u linijama 14-16 pronalazi početak novog ciklusa.

Da bismo provjerili ispravnost algoritma, promotrimo elemente A[i] i A[j]. Bezsmanjenja općenitosti neka je A[i] ≤ A[j]. Promotrimo slučaj kad je i < j, slučaj kadje i > j se dokazuje analogno. Kako je bA[i]c ≤ bA[j]c, element A[i] ide u istu klasukao i A[j] ili u klasu s nižim indeksom. Ako elemente A[i] i A[j] treba staviti u istuklasu, treba pokazati da će ih algoritam postaviti na različita mjesta unutar te klase.A, tomu je tako jer element A[i] linija 21 stavlja na mjesto L[bm · flashc] u nizu A,

nakon čega se L[bm · flashc] dekrementira u liniji 23 te tako više ni jedan elementneće biti stavljen na to mjesto. Konačno, linija 25 elemente A[i] i A[j] stavlja u praviporedak. Ako se A[i] i A[j] smještaju u različite klase, onda se samim time nalaze uodgovarajućem poretku.

Analizirajmo sada izvršno vrijeme flash sorta. Petlja for u linijama 5-6 zahtijevaΘ(n) vremena. For petlje u linijama 3-4 te 8-9 zahtijevaju Θ(m) vremena. Kako je upraksi m = n/k za neku malu konstantu k, znači da sve tri for petlje zahtijevaju Θ(n)vremena. While petlja u linijama 18-24 se očito odvija n puta jer se svaki elementstavlja u odgavarajuću klasu samo jednom. Provjerimo još vremensku složenost whilepetlje u linijama 14-16. Algoritam će ući u tu petlju c− 1 puta, gdje je c broj ciklusapotrebnih da bismo došli do konačne permutacije. No, valja primijetiti da ukupanbroj prolazaka kroz petlju, bez obzira na broj ciklusa, ne može biti veći od n − 1, jerpetlja svaki puta kreće od onog elementa i na kojemu je zadnji puta stala. Ostaje zaprovjeriti izvršno vrijeme linije 25. Kako izvršno vrijeme insertion sorta ovisi o sumiudaljenosti elmenata od njihovih pravih mjesta, pozivanje insertion sorta na cijeli niza

16

Page 20: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

A je ekvivalentno pozivanju insertion sorta na svaku od m klasa posebno. A, kakosmo vidjeli u prethodnom poglavlju, dovoljan uvijet da bi izvršno vrijeme m pozivainsertion sorta bilo linearno jest da svaka klasa sadrži približno jednak broj (n/m)elemenata.

Lako je vidjeti da su bucket sort i flash sort vrlo slični. Ono što ih razlikuje jestčinjenica da bucket sort koristi dodatni niz da bi premjestio elemente u odgovarajućeklase, dok flash sort radi u mjestu te na taj način koristi manje memorije. No, štedećimemoriju flash sort postaje nešto (konstantno puta) sporiji, u odnosu na bucket sort,u što ćemo se i uvjeriti u sljedećem poglavlju.

17

Page 21: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Poglavlje 2

Testiranje algoritama za sortiranje

U prethodnom poglavlju smo proučili četiri algoritma za sortiranje, koji pod određenimpretpostavkama imaju linearno vrijeme izvršenja, što znači da bi ti algoritmi trebalibiti brži od bilo kojeg algoritma koji sortira uspoređivanjem, pod uvjetom da je nizkoji se sortira dovoljno velik. U ovom poglavlju ćemo provjeriti koliko su ti algoritmizaista brzi u praksi te kako promjene određenih parametara, kao što su veličina niza,raspon i tip podataka, utječu na njihove preformanse. Svi algoritmi su implementi-rani u programskom jeziku C++. Implementacija radix sorta je rad A. Reinalda, P.Harrisa, R. Rohera i D. Jagdmanna [2]. Naime, riječ je o veoma dobro optimiziranojimplementaciji koja dobro radi na veoma različitim tipovima podataka, u što ćemo sei uvjeriti u ostatku ovog poglavlja. Ostale algoritme (counting sort, bucket sort i flashsort) sam implementirao samostalno.

Vrijeme izvršenja je mjereno funkcijom clock() iz ctime biblioteke te uspoređeno sSTL (Standard Template Libary) funkcijom sort(). Funkcija sort() jest zapravo im-plementacija intro sorta standardno ugrađena u Microsoft Visual Studio C++ te kaotakva pretstavlja optimalnu klasu algoritama za sortiranje uspoređivanjem, tj. njenovrijeme izvršenja je jednako Θ(n lg n).

Ova implementacija intro sorta, ukratko, radi na sljedeći način: Za sortiranje sekoristi median od 3 quick sort ("median od 3" znači da se za pivotni element odabiremedinan od prvog, srednjeg i posljednjeg elementa, tj. p = med A[1], A[n/2], A[n].)sve dok je broj particija, početnog niza od n elemenata, manji od 1.5 lg n. Ako se tagranica pređe, koristi se heap sort. Također, za n ≤ 32 se koristi insertion sort.

Kako funkcija sort() radi u Θ(n lg n) vremenu, dok preostala četiri algoritma radeu linearnom vremenu. Kada kažemo da ti algoritmi rade u linearnom vremenu, naumu trebamo imati da za takvo što moraju biti ispunjene određene pretpostavke, tj.raspon podataka mora biti relativno malen za counting sort, dok za bucket sort iflash sort moramo poznavati distribuciju iz koje dolaze podaci. Pod uvjetom da su tepretpostavke ispunjene, za očekivati je da će za dovoljno velike n ti algoritmi biti bržiod funkcije sort(). Za koje n ti algoritmi zaista postaju brži možemo vidjeti u tablici2.1 te na slici 2.1.

18

Page 22: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

n counting sort radix sort bucket sort flash sort sort()2 487 25 14 7 522 498 26 14 8 523 511 27 15 8 824 528 27 16 8 1625 537 28 20 14 4126 549 28 21 14 5127 555 28 22 17 11328 567 36 33 26 27229 578 56 64 64 651210 590 101 95 106 2 800

Tablica 2.1: Vremena izvršenja, mjerena u mikrosekundama, za različite n (duljine niza) koji sesortira. Mjerenja su vršena na nizovima od n uniformno distribuiranih cijelih brojeva iz segmenta[0, 32767].

Za razliku od ostalih mjerenja, vremena izvršenja iz tablice 2.1 su, radi veće pre-ciznosti, mjerena pomoću funkcija QueryPerformanceCounter i QueryPerformanceFre-quency iz Windows.h biblioteke.

Slika 2.1 zorno prikazuje kako izvršno vrijeme funkcije sort() raste znatno brženego što je to slučaj kod preostala četiri algoritma, što je, poznavajući složenost te-stiranih algoritama, i bilo za očekivati. Također, valja napomenuti da se testiraneimplementacije algoritama za sortiranje u linearnom vremenu mogu dodatno ubrzati,za male n, koristeći insertion sort, kako to radi i sama funkcija sort().

n counting sort radix sort bucket sort flash sort sort()215 3 4 3 4 66216 4 5 5 6 132217 7 9 8 10 275218 19 18 21 24 559219 26 38 73 101 1 093220 49 79 201 275 2 109221 93 156 453 624 3 946222 202 312 999 1 248 7 769223 390 655 2 060 2 496 15 850224 795 1 373 4 368 5 351 31 231225 1 638 2 808 9 579 11 607 61 526226 3 666 5 429 20 311 25 397 126 407

Tablica 2.2: Vremena izvršenja, mjerena u milisekundama, za različite n (duljine niza) koji se sortira.Mjerenja su vršena na nizovima od n uniformno distribuiranih cijelih brojeva iz segmenta [0, 32767].

Na slici 2.2 vidimo da su sva četiri algoritma za sortiranje u linearnom vremenu brži

19

Page 23: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Slika 2.1: Grafički prikaz vremena izvršenja iz tablice 2.1.

Slika 2.2: Grafički prikaz vremena izvršenja iz tablice 2.2.

20

Page 24: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

od funkcije sort(), što je u skladu s našom pretpostavkom s početka ovog poglavlja.Primijetimo da se bucket sort i flash sort ponašaju vrlo slično, samo što je flash sortmalo sporiji. To usporenje flash sort duguje činjenici da obavlja permutacije elemenatau mjestu, no iz istog razloga koristi nešto manje memorije. Također, zanimljivo je dapodaci iz tablice 2.2 pokazuju da je radix sort koji koristi counting sort za stabilnosortiranje sporiji od samog counting sorta. Zašto bismo onda uopće željeli koristitiradix sort koji ima složeniji kod, a sporiji je od counting sorta?

k counting sort radix sort bucket sort flash sort sort()210 192 364 1 055 1 496 9 548211 199 365 1 060 1 482 9 532212 202 365 1 045 1 467 9 563213 205 353 1 061 1 482 9 563214 215 359 1 061 1 482 9 563215 234 361 1 055 1 496 9 563216 250 374 1 060 1 482 9 548217 265 343 1 045 1 467 9 532218 359 359 1 061 1 482 9 563219 609 359 1 061 1 482 9 563220 858 359 1 061 1 482 9 563221 983 374 1 045 1 497 9 548222 1 092 358 1 029 1 497 9 563223 1 154 359 1 045 1 497 9 547224 1 311 359 1 077 1 498 9 532225 1 575 344 1 045 1 497 9 578226 1 996 359 1 061 1 482 9 594

Tablica 2.3: Vremena izvršenja za različite k (raspone podataka). Mjerenja su vršena na nizovimaod n = 5 · 106 uniformno distribuiranih cijelih brojeva iz segmenta [0, k − 1].

Kao što vidimo u tablici 2.3, odnosno na slici 2.3, što je raspon podataka k veći,to je counting sort sporiji, što je očekivano, uzmemo li u obzir da je vrijeme izvršenjacounting sorta Θ(n+k). S druge strane, ni jedan od preostala četiri algoritma, pa takoni radix sort, očito ne ovisi o k. To smo mogli i očekivati jer testirana implementacijaradix sorta radi na znamenkama od 8 bitova pa je k = 28 − 1 = 255, bez obzira naukupni raspon podataka. Također, očekivana vremena izvršenja bucket sorta i flashsorta ovise isključivo o tome jesu li elementi ulaznog niza u jednakom broju raspoređenimeđu klasama koje se kasnije sortiraju insertion sortom. Znači, za malene k countingsort je brz, no ako je k velik, radix sort se nameće kao bolji izbor.

Promotrimo sada što se događa promijenimo li duljinu bitnog zapisa. Kao štovidimo na slici 2.4, vrijeme izvršenja svih algoritama, osim funcije sort(), raste s poras-tom duljine bitnog zapisa. To je zato što operacije pridruživanja (=), koje čine velikdio izvršnog vremena kod tih algoritama, "koštaju" nešto više, za dulji bitni zapis.

21

Page 25: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Slika 2.3: Grafički prikaz vremena izvršenja iz tablice 2.3.

Slika 2.4: Grafički prikaz vremena izvršenja iz tablice 2.4.

22

Page 26: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

b counting sort radix sort bucket sort flash sort sort()8 140 94 406 452 4 88316 156 156 390 437 4 88332 172 344 577 671 4 80564 374 780 780 967 5 039

Tablica 2.4: Vremena izvršenja za različite b (duljine bitnog zapisa). Mjerenja su vršena na nizovimaveličine n = 5 ·106 uniformno distribuiranih cijelih brojeva iz segmenta [0, 255]. Tip podataka korištenu testiranju je b-bitni unsigned integer.

No, od svih algoritama, posebno se ističe radix sort, čije vrijeme izvršenja rastaznatno brže nego kod ostalih. To je u skladu s propozicijom 1.2, prema kojoj je složenostalgoritma radix sorta jednaka Θ((b/r)(n+2r)), što znači da izvršno vrijeme radix sortalinearno ovisi o duljini bitnog zapisa b.

Dosad smo se isključivo bavili nizovima čiji su elementi uniformno distribuirani cijelibrojevi, na kojima bucket sort i flash sort imaju linearno očekivano vrijeme izvršenja.Promotrimo sada što se događa kada ako brojevi nisu iz uniformne distribucije.

radix sort bucket sort flash sort sort()n unif Cauchy unif Cauchy unif Cauchy unif Cauchy

215 4 4 3 105 4 154 66 62216 5 5 5 310 6 313 132 132217 9 9 8 622 10 623 275 274218 18 19 21 1 236 24 1 239 559 549219 38 37 73 2 459 101 2 459 1 093 1 123220 79 77 201 4 895 275 4 895 2 109 2 090221 156 156 453 9 563 624 9 610 3 946 4 181222 312 312 999 18 704 1 248 18 704 7 769 8 096223 655 624 2 060 35 677 2 496 35 739 15 850 16 318224 1 373 1 248 4 368 65 052 5 351 65 442 31 231 32 323225 2 808 2 480 9 579 108 654 11 607 109 387 61 526 63 070

Tablica 2.5: Usporedba vremena izvršenja. U neparnim stupcima su vremena izvršenja za uniformnodistribuirane cijele brojeve iz segmenta [0, 32767], a u parnim, vremena izvršenja za slučajno generiranebrojeve iz Cauchijeve distribucije.

U tablici 2.5 su navedena vremena izvršenja, u milisekundama, za pojedine algo-ritme, mjerena na slučajno generiranim brojevima iz uniformne, odnosno Cauchyjevedistribucije pri čemu je F (x) = arctg x

π+ 1

2 funkcija distribucije Cauchyjeve slučajnevarijable.

Kao što možemo vidjeti na slici 2.6 bucket sort i flash sort su znatno sporiji napodacima iz Cauchijeve distribucije nego na podacima iz uniformne distribucije, dok

23

Page 27: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Slika 2.5: Funkcija gustoće Cauchyjeve slučajne varijable s crveno označenim podintervalima. (a)vjerojatnost da se slučajno odabrani element iz Cauchijeve distribucije nalazi u bilo kojem od 10podintervala je jedna 1/10, (b) ekvidistantna podjela podintervala. Cauchijeva distribucija generiranajviše brojeva bliskih nuli te su podintervali blizu nule najkraći.

vremena izvršenja radix sort i STL funkcije sort() ne ovise o distribuciji iz koje dolazedani podaci. Bucket sort i flash sort su tako spori jer u neke klase smještaju malo,a u neke veoma mnogo elemenata te tako ne uspijevaju iskoristiti brzinu insertionsorta koja se očituje samo na nizovima s malim brojem elemenata. Tomu je takojer, pretpostavljajući uniformnu distribuciju podataka, bucket sort i flash sort cijeliinterval, iz kojeg dolaze podaci, dijele na podintervale jednake veličine (kao na slici2.5 (b)), a kako Cauchyjeva slučajna varijabla generira najviše brojeva bliskih nuli ivrlo malo svih ostalih brojeva, to znači da će u podintervale blizu nule biti smještenodaleko najviše elemenata ulaznog niza.

Primijetimo da radix sort ovdje radi na brojevima koji dolaze iz Cauchyjeve dis-tribucije i koji su kao takvi racionalni, iako smo u poglavlju 1.3. zahtijevali da po-daci nad kojima radi radix sort budu cijeli brojevi. U testiranoj implementaciji radixsorta to je postignuto korištenjem operatora reinterpret_cast, koji se koristi za pre-vođenje racionalnog tipa podataka u odgovarajući cjelobrojni tip. Naime, kada unutarradix sorta koristimo counting sort za sortiranje po i-toj znamenci (u testiranoj im-plementaciji i-tu znamenku čini i-ti bayte), problem se pojavljuje u petoj liniji našeg

24

Page 28: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Slika 2.6: Grafički prikaz vremena izvršenja iz tablice 2.5.

pseudokoda counting sorta.4 for j = 1 to length(A)5 C[A[j]] = C[A[j]] + 1

Kao što vidimo kao indeks niza C se koristi element ulaznog niza A[j] koji jeracionalan broj, a indeks niza može biti samo nenegativan cijeli broj. Zato se u testi-ranoj implementaciji u liniji 5 umjesto A[j] koristi

∗ reinterpret_cast<int8∗>(&A[j]), (2.1)

gdje je int8 8-bitni cijeli broj. int8 se koristi jer se sortiranje odvija po i-toj znamencikoja se također sastoji od 8 bitova. Rezultat izraza 2.1 je 8-bitni cijeli broj dobivenjednostavnim kopiranjem binarnog zapisa od A[j] koji se zatim interpretira kao cjelo-brojni tip podataka int8. Valja napomenuti da duljina bitnog zapisa znamenke pokojoj se sortira mora biti jednaka duljini bitnog zapisa cjelobrojnog tipa podataka ukoji se ta znamenka prevodi. U protivnom, kada bismo primjerice 16-bitnu znamenku(racionalnog broja) pretvarali u 8-bitni cijeli broj, moglo bi se dogoditi da se dvijerazličite znamenke preslikaju u isti cijeli broj.

Kao što smo vidjeli u poglavljima 1.4. i 1.5., da bi bucket sort i flash sort imalilinearno očekivano vrijeme izvršenja, nije neophodno da podaci dolaze iz uniformnedistribucije. Dovoljno je da se u svakom od podinetrvala nalazi približno jednak brojelemenata niza. Za uniformnu distribuciju U(0, 1), klasu koju ćemo staviti element xse određuje formulom k = bnxc, gdje je k redni broj klase, a n broj elemenata nizakoji se sortira. Za uniformnu distribuciju s parametrima a i b, U(a, b), odgovarajuća

25

Page 29: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

formula glasi

k =⌊n(x− a)b− a

⌋.

Ta formula je korištena u našim implementacijama bucket sorta i flash sorta.Primijetimo da su x te (x − a)/(b − a) zapravo karakteristični dijelovi funkcija

distribucije slučajnih varijabli U(0, 1) i U(a, b), jer su odgovarajuće funkcije distribucije

F0,1(x) =

0 , za x ≤ 0x , za x ∈ (0, 1]1 , inače

za standardnu uniformnu slučajnu varijablu te

Fa,b(x) =

0 , za x ≤ ax− ab− a

, za x ∈ (a, b]1 , inače

za uniformnu slučajnu varijablu s parametrima a i b. Lako se provjeri da se u općemslučaju redni broj klase u koju treba staviti broj x može odrediti formulom

k = nF (x), (2.2)

gdje je F (x) funkcija distribucije odgovarajuće slučajne varijable.

bucket sort flash sortn unif Cauchy Cauchy[mod] unif Cauchy Cauchy[mod]

215 3 105 16 4 154 16216 5 310 31 6 313 32217 8 622 47 10 623 48218 21 1 236 94 24 1 239 109219 73 2 459 249 101 2 459 265220 201 4 895 515 275 4 895 655221 453 9 563 1 061 624 9 610 1 342222 999 18 704 2 138 1 248 18 704 2 606223 2 060 35 677 4 368 2 496 35 739 5 772224 4 368 65 052 8 798 5 351 65 442 11 903225 9 579 108 654 18 440 11 607 109 387 23 805

Tablica 2.6: Usporedba vremena izvršenja. U prva tri stupca se nalaze vremena izvršenja zabucket sort, za podatke iz uniformne distribucije, Cauchyjeve distribucije i Cauchyjeve distribucije smodificiranom formulom za određivanje klase u koju treba staviti određeni element te analogno zaflash sort u sljedeća tri stupca.

U tablici 2.6 vidimo vremena izvršenja za bucket sort i flash sort mjerena n po-dacima iz, redom, uniformne distribucije, Cauchyjeve distribucije (podintervali kao na

26

Page 30: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

slici 2.5 (b)) te iz Cauchyjeve distribucije s prilagođenom formulom za određivanje klase(podintervali kao na slici 2.5 (a)). Preciznije, u ovom slučaju formula glasi

k =⌊n(arctg x

π+ 1

2

)⌋,

jer je funkcija distribucije Cauchyjeve slučajne varijable

F (x) = arctg xπ

+ 12 .

Slika 2.7: Grafički prikaz vremena izvršenja iz tablice 2.6.

Na slici 2.7 možemo vidjeti da su algoritmi s modificiranom formulom za izračunklase znatno brži od onog s uobičajenom formulom. Ipak, tako prilagođeni algoritminisu jednako brzi kao oni sa standardnom formulom na podacima iz uniformne distribu-cije. Tomu je tako, jer je izračun same formule za određivanje klase za Cauchyjevudistribuciju, koja se mora računati barem jednom za svaki od n elemenata niza, znatnosloženiji nego što je to u slučaju uniformne distribucije.

U ovom poglavlju smo vidjeli kako naši algoritmi za sortiranje u linearnom vremenufunkcioniraju u praksi te njihove performanse usporedili sa STL funkcijom sort() kojaradi u Θ(n lg n) vremenu. Uspoređujući međusobno vremena izvršenja C++ imple-mentacija tih algoritama na različitim podacima, uočili smo njihove najveće prednostii mane. Counting sort je brz u slučaju kad je raspon podataka k malen. Brzina radixsorta ovisi o duljini bitnog zapisa koji se koristi za podatke. Ako pogrešno procijenimodistribuciju iz koje dolaze podaci, bucket sort i flash sort postaju veoma spori. Flashsort je na jednakim podacima uvijek sporiji od bucket sorta, ali koristi manje memorije.

27

Page 31: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Zaključak

Još od početaka razvoja računalne znanosti pa sve do danas problem pronalaženja štoefikasnijeg algoritma za sortiranje predstavlja jedno od najistraživanijih područja uinformatici. Razlozi za to su mnogostruki, od onih čisto praktičnih kao što su uštedavremena, novca i energije pa sve do dobro nam poznate akademske znatiželje.

U ovom radu smo proučili četiri algoritma koji, pod uvjetom da zadovoljavajuodređene pretpostavke, imaju linearno vrijeme izvršenja. Prva dva među njima, count-ing sort i radix sort, se bave problemom sortiranja cijelih brojeva. No, kao što smovidjeli u prethodnom poglavlju, takvi algoritmi se lako mogu prilagoditi za rješavanjeopćeg problema sortiranja, što je i očekivano uzmemo li u obzir način na koji se podacizapisuju u današnjim računalima.

Ni za jedan od algoritama promatranih u ovom radu ne možemo reći da je općenitonajbolji, ili pak najbrži, ali možemo reći da su svi uglavnom brži od STL funkcije sort(),osim u nekim posebnim situacijama. Još jedno zanimljivo svojstvo koje smo mogliprimijetiti jest proporcionalni odnos između brzine algoritma i potrošnje memorije. Otome koji algoritam za sortiranje je najbolje koristiti u datoj situaciji, ovisi o strukturiulaznih podataka koje treba sortirati te hardwareu kojim raspolažemo.

28

Page 32: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

Literatura

[1] T. H. Cormen, C. E. Leiserson, R. L. Rivest, C. Stein, Introduction to Al-gorithms, 3rd ed., MIT Press, Cambridge, Massachusetts, 2009.

[2] http://cubic.org/docs/radix.htm, 1.2.2012.

[3] D. E. Knuth, The Art of Computer Programming, Volume 3: Sorting and Search-ing, Addison-Wesley, Reading, Massachusetts, 1973.

[4] K. D. Neubert, The Flashsort Algorithm, Dr. Dobb’s Journal, 1998.http://drdobbs.com/database/184410496

[5] http://videolectures.net/mit6046jf05_demaine_lec05, 1.2.2012.

29

Page 33: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

SažetakOvim radom se opisuju četiri algoritma za sortiranje u linearnom vremenu: countingsort, radix sort, bucket sort i flash sort. Algoritmi su analizirani s teoretskog i prak-tičnog gledišta. C++ implementacije tih algoritama su testirane te su njihova vremenaizvršenja uspoređena s onima STL funkcije sort(), koja radi u Θ(n lg n) vremenu.

Ključne riječi: Counting sort, radix sort, bucket sort, flash sort, sortiranje, linearnovrijeme, C++

AbstractThis paper describes four different linear time sorting algorithms: counting sort, radixsort, bucket sort and flash sort. They are analyzed from both theoretical and practicalpoint of view. C++ implementations of these algorithms are tested and their runningtimes compared aginst those of STL function sort(), which runs in Θ(n lg n) time.

Keywords: Counting sort, radix sort, bucket sort, flash sort, sorting, linear time,C++

30

Page 34: SveučilišteJ.J.StrossmayerauOsijeku Odjelzamatematiku ...mdjumic/uploads/diplomski/PEJ31.pdf · jednostavnijih kao što su bubble sort i insertion sort, čije vrijeme izvršenja

ŽivotopisRođen sam 27. rujna 1987. u Beničancima. Godine 1994. upisujem prvi razred upodručnoj školi u Beničancima, koju pohađam sljedeće četiri godine. Preostala če-tiri razreda osnovne škole sam završio u OŠ Matija Gubec u Magadenovcu. Po za-vršetku svog osnovnoškolskog obrazovanja upisujem prirodoslovno matematičku gim-naziju Isidora Kršnjavoga u Našicama, koju uspješno završavam 2006. godine. Daljnjeobrazovanje nastavljam na Preddiplomskom studiju matematike na Odjelu za matem-atiku u Osijeku. Studij završavam u roku te stječem akademski naziv prvostupnikamatematike. Trenutno sam apsolvent Sveučilišnog nastavničkog studija matematike iinformatike na istom fakultetu.

31