You are on page 1of 3

Uvod Algoritam je nain za rjeavanje odreenog problema.

Sortiranje je problem koji postoji otkad su raunala prestala biti ograniena na samo jedan program, odnosno kad se pojavio pojam (softverskog) programiranja. Premda se naizgled ne radi o bitnom problemu sortiranje se javlja u ogromnom broju programa i kao dio jo veeg broja drugih algoritama. Postoje deseci razvijenih i detaljno analiziranih algoritama za sortiranje, a ovaj lanak je posveen jednom relativno jednostavnom (i u ideji, i u implementaciji) i vrlo efikasnom algoritmu Shell sortu. Prije njega bit e objanjeno neto manje efikasno, ali zato gotovo trivijalno sortiranje Insertion sort. Insertion sort, premda se za vee nizove podataka performansama ne moe mjeriti sa Shell sortom, ipak ima vie nego dobre rezultate s manjim nizovima. Osim toga, efikasniji je od podjednako jednostavnog Bubble sorta koji je ee spominjan. Insertion sort Zamislimo da trebamo sortirati sljedei niz: 5 1 2 4 3 Sortirati neki niz A znai pretvoriti ga u niz B iji su elementi ujedno i elementi niza A, tako da vrijedi: b1 b2 ... bn Najjednostavnije tehnike kojima bi se to moglo postii su Insertion, Bubble i Selection sort. No, ovaj tekst govori o Shell sortu pa u objasniti samo Insertion sort jer je on ustvari dio Shell sorta. Osnovna ideja Insertion sorta je prolaziti kroz svaki element (osim prvog), usporediti ga sa prethodnim elementima, pronai ispravnu poziciju meu prethodnim elementima, i premjestiti ga na tu ispravnu poziciju (dakle, ta pozicija se nalazi u intervalu [1, i], gdje je i pozicija trenutnog elementa u prolazu. Pronalaenje ispravne pozicije i-tog elementa se odvija for-petljom prolazimo kroz svaki element dok ne doemo do elementa koji je manji od i-tog elementa. Na taj nain je u svakom trenutku niz sortiran do pozicije i (pozicije u tom trenutku). Ovako bi izgledali koraci Insertion sorta na nizu u gornjem primjeru (parovi uglatih zagrada [ ] se nalaze oko elementa kojeg trenutno promatramo, prije nego to ga premjestimo): 5 [1] 2 4 3 u: 1 5 2 4 3 Nema elementa manjeg od 1, pa 1 ide na poetak. Mijenjamo niz

1 5 [2] 4 3 1 je prvi element manji od 2, pa umeemo 2 nakon 1. Niz je sad: 1 2 5 4 3 1 2 5 [4] 3 1 2 4 5 [3] 2 je prvi element manji od 4, pa niz mijenjamo u: 1 2 4 5 3 2 je prvi element manji od 3, pa niz mijenjamo u: 1 2 3 4 5

Ovo je pomalo apstraktan prikaz Insertion sorta, jer je koritena rije umetanje, a nije objanjeno kako se tono to umetanje vri. Razlog je to e se umetanje u polju vriti premjetanjem desno svih elemenata izmeu i-tog elementa i ispravne pozicije i-tog elementa. U vezanoj listi e se samo promijeniti pokaziva (ili pokazivai, ako je dvostruko vezana). U pseudokodu, ovako izgleda (indexi su 1-based, implementacija je namijenjena za polje):

Insertion sort(A, n) Za i = [ 2 , n ]: // kroz svaki element u nizu Za j =[ i 1, 1 ]: // kroz sve elemente do i-tog Ako je A[j + 1] < A[j] onda: zamijeni(A[j], A[j + 1]) // premjetamo i-ti elemen

Kolika je algoritamska sloenost Insertion sorta? Premda cilj ovog teksta nije matematika analiza pomou raznih notacija, dobro je znati kakve performanse moete oekivati od nekog algoritma. U najboljem sluaju, polje e ve biti sortirano. Insertion sort e u ovom, najboljem, sluaju napraviti n 1 provjera, i 0 premjetanja. Vrijeme izvravanja e rasti linearno s brojem elemenata, npr. za 10 elemenata obavit e se 10K provjera. K je konstanta koja ovisi o raunalu na kojem je sort pokrenut na bilo kojem imalo novijem raunalu bit e zanemariv (K 0). U veini sluaja e ipak vrijeme izvravanje rasti kvadratno s brojem elemenata - n, to ga ini loim izborom za visoke n. Koliko provjera i premjetanja e izvriti u najgorem sluaju? Najgori sluaj je kad vrijedi a1 > a2 > ... > an - dakle, kad je su elementi niza u obrnutom redu od sortiranog. Primjer: 5 4 3 2 1 4 5 3 2 1 3 4 5 2 1 2 3 4 5 1 1 2 3 4 5 Prije sortiranja, ovako izgleda niz. 1 premjetanje 2 premjetanje 3 premjetanje 4 premjetanje

Broj premjetanja moemo dovesti u vezu s n-om. Broj iznosi: Ako sad iz ovog izraza odbacimo konstante i mononome nieg stupnja od 2 dobivamo N2, dakle prilino loe performanse za visoke n - ali ako gledamo konstante i mononom prvog stupnja, performanse su sasvim solidne s obzirom da se radi o najgorem sluaju. Shell sort Pogledajmo jo jednom Insertion sort. Koji je njegov najvei nedostatak? U kojem tipu situacije e imati najbolje performanse? Odgovor na prvo pitanje je sporost koja se dogaa u sluajevima kad se element nalazi daleko od svog cilja. To se vidi u primjeru iznad - najgora situacija je kad su elementi potpuno obrnuto sortirani. Postoji li nain da se smanji taj razmak? Na prvi pogled ne, ako i postoji vjerojatno je previe zahtjevan (u smislu procesorskih i memorijskih resursa). No, moda bi se svejedno tako neto moglo isplatiti, jer je za Insertion sort lako pokazati da je vrlo efikasan kad je razmak malen (to je odgovor na drugo pitanje) - a to je manji to e manji biti i rast funkcije vremena izvravanja. Dakle, cilj je pronai neki nain za "polusortiranje" koji e biti dovoljno brz da sortira to je mogue vie elemenata u relativno kratkom vremenu.

Logino, za polusortiranje emo koristiti neki algoritam za sortiranje (ili modifikaciju postojeeg) - samo je pitanje koji. Nakon polusortiranja, napravit emo pravo sortiranje Insertion sortom (iznimno efikasnim u ovom sluaju). Ono to Shell sort ini zanimljivim je da se za polusortiranje koristi - Insertion sort! Kako izvesti polusortiranje? Do odgovora na to pitanje se dolazi analizom odgovora na pitanje postavljeno na poetku odlomka - koji je najvei nedostatak Insertion sorta. Ako veliki razmaci ine problem, zato ih ne smanjiti? Umjesto da usporeujemo a1, a2... usporeivat emo a0, ak, a2k... Dakle, svaki k-ti element. Na taj nain e elementi puno bre putovati prema svom vjerojatnom cilju. Nakon prolaska kroz svaki k-ti element, proi emo kroz svaki 1+(k)-ti element. Nakon toga svaki 2+(k)-ti element. Broj s kojim zbrajamo k je ustvari "offset", on e se poveavati dok ne postane k - 1. Ono to pokuavamo svime ovime je razlomiti niz na polunizove, gdje je svaki element nekog poluniza od susjednog elementa istog poluniza u originalnom nizu bio udaljen za k. Prije nastavka, pogledajmo primjer rastavljanja na polunizove za dvije vrijednosti k: Originalni niz: 1 2 3 4 5 6 7 8 9 Ako je k = 2, Prvi poluniz: 1 3 5 7 9 Drugi poluniz: 2 4 6 8

Ako je k = 4, Prvi poluniz: 1 5 9 Drugi poluniz: 2 6 Trei poluniz: 3 7 etvrti poluniz: 4 8 Ideja je da ovo lomljenje nizova, i zatim njihovo unutarnje sortiranje, obavljate vie puta. Svaki put, s razliitim k. Osnovni i jedini problem Shell sorta je kako odabrati niz k-ova koji e dati najbolje rezultate prilikom sortiranja. U prvom prolazu k e biti velik, svakim daljnjim prolazom se sve vie smanjuje. Bitno je rei da ne postoji savreni niz (barem jo nije otkriven) koji bi dao najbolje performanse. No, postoje neki nizovi koji su ee koriteni.