You are on page 1of 46

ALGORITMI I STRUKTURE

PODATAKA
- ALGORITMI ZA SORTIRANJE -


Prof. Duan Starevi
Literatura
Dejan ivkovi, Osnove dizajna i analize
algoritama, CET, Beograd, 2007
Robert Manger, Miljenko Marui,
Strukture podataka i algoritmi, PMF
Zagreb, skripta, 2007
ppt prezentacije D. Kalpia i kolega sa
FER-a, Zagreb, 2007
Problem sortiranja
Problem (rastueg) sortiranja
Zadata je lista (a1, a2, . . . ,an) duine n. Vrednosti
elemenata liste mogu se meusobno uporeivati po
kriterijumu <= . Treba permutovati vrednosti
elemenata liste tako da nakon permutovanja bude
a1 <= a2 <= . . . <= an.
Algoritam za sortiranje je bilo koji algoritam koji reava
opisani problem
Opisaemo nekoliko algoritama za sortiranje, pokazati
primere njihovog rada, te analizirati njihovu vremensku
sloenost
Problem sortiranja
Zbog jednostavnosti pretpostavljamo da lista sastoji od
celih brojeva, kao i da je implementirana poljem duine
barem n.
Dakle, umesto o sortiranju liste (a1, a2, . . . ,an)
govoriemo o sortiranju polja a[ ] koje se sastoji od
elemenata a[0],a[1], . . . , a[n-1] tipa int.
Algoritmi se mogu umesto na cele brojeve primeniti i na
podatke nekog drugog tipa, pod uslovom da za te
podatke imamo odgovarajuu operaciju uporeivanja
Svaki od algoritama za rastue sortiranje moe se na
trivijalni nain pretvoriti u opadajue sortiranje.
Problem sortiranja zamenom
mesta elemenata
Jednostavni postupci sortiranja:
sortiranje izborom najmanjeg elementa
(selection sort),
sortiranje zamjenom susjednih elemenata
(bubble sort).
Oba algoritma sa zamenom elemenata
imaju slinu (kvadratnu) vremensku
sloenost i sporiji su od veine drugih
algoritama

Sortiranje izborom najmanjeg
elementa (selection sort)
Algoritam radi tako to se proe poljem, pronae najmanji element i
potom zameni s poetnim elementom
Postupak se ponavlja na ostatku polja (polje bez poetnog
elementa)
Da bi se celo polje sortiralo potrebno je n 1 prolazaka

Sortiranje izborom najmanjeg
elementa (selection sort)
Algoritam sortiranja izborom najmanjeg elementa
(selection sort) napisaemo u C jeziku kao funkciju
selectionSort()
Fukcija selectionSort() ima dva argumenta: celobrojno
polje a[ ] i njegovu duinu n
Funkcija menja polje a[ ] tako da ono postane sortirano
Pomona funkcija swap() slui za zamenu vrednosti
izmeu dve celobrojne varijable zadate svojim adresama
Sortiranje izborom najmanjeg
elementa (selection sort)

void selectionSort (int a[], int n) {
int i, j, min;
for (i = 0; i < n; i++) {
min = i;
for (j = i+1; j < n; j++)
if (a[j] < a[min]) min = j;
swap(&a[i], &a[min]);
}
}
Sortiranje izborom najmanjeg
elementa (selection sort)

void swap (int *x, int *y) {
int aux;
aux = *x;
*x = *y;
*y = aux;
}
Selection sort: analiza
vremenske sloenosti
U prvom prolasku imamo n1 uporeenja, a u svakom
iduem prolasku broj uporeenja se smanji za 1
Dakle ukupni broj usporedbi iznosi:
(n 1) + (n 2) + (n 3) + + 2+1 = n(n 1)/2.
U svakom prolasku postoji jo razmena vrednosti dve
varijable, pa imamo jo 3(n 1) operacija pridruivanja
Dakle ukupni broj operacija je :
n(n 1)/2+ 3(n 1) = O(n
2
).
Algoritam obavlja isti posao bez obzira na poetno
stanje polja, ak i ako je polje ve na poetku bilo
sortirano!
Sortiranje zamenom susednih
elemenata (bubble sort)
Prolazimo poljem od poetka prema kraju i
usporeujemo susedne elemente
Ako je neki element vei od sledeeg elementa,
zamenimo im vrednosti
Kada doemo do kraja polja, najvea vrednost doi e
na poslednje mesto
Opisani postupak ponavljamo na skraenom polju (polje
bez poslednjeg elementa)
Algoritam se sme zaustaviti ako se u nekom prolazu
ustanovi da nema parova elemenata koje bi trebalo
zameniti
Sortiranje zamenom susednih elemenata (bubble sort)

Sortiranje zamenom susednih
elemenata (bubble sort)
Funkcija bubbleSort() implementira u jeziku C algoritam
sortiranja zamjenom susednih elemenata (bubble sort)
Funkcija prima kao argumente cjelobrojno polje a[ ] i
njegovu duinu n
Funkcija menja polje a[ ] tako da ono postane sortirano
Koristi se ista pomona funkcija swap() za razamenu
vrednosti dve celobrojne varijable
Sortiranje zamenom susednih
elemenata (bubble sort)

void bubbleSort (int a[], int n) {
int i, j;
for (i = 0; i < n-1; i++)
for (j = 0; j < n-1-i; j++)
if (a[j+1] < a[j])
swap(&a[j], &a[j+1]);
}
Bubble sort : analiza vremenske
sloenosti
U prvom prolazu imamo u najgorem sluaju n 1
poreenja i n 1 zamena elemenata
U drugom prolazu imamo u najgorem sluaju n 2
usporedbi i n 2 zamena elemenata
. . . . . . .
U (n 1)-vom prolazu imamo u najgorem sluaju 1
poreenje i 1 zamenu elemenata
Dakle, ukupan broj operacija u najgorem sluaju iznosi:
4(n 1) + 4(n 2) + + 41 = 4n(n 1)/2 = 2n(n 1).
Ocenjeni broj operacija zaista se dobiva kad su elementi
poetnog polja sortirani u opadajuem poretku
Bubble sort : analiza vremenske
sloenosti
S druge strane, ako je poetno polje ve sortirano u
rastuem poretku, obavie se samo jedan prolaz s n1
poreenja i 0 zamjena.
Za bilo koje drugo ureenje poetnog polja broj operacija
je izmeu (n 1) i 2n(n 1).

U svakom sluaju, vreme izvoena je O(n
2
)
Sortiranje umetanjem
Razmatramo algoritme za sortiranje koji se svode na
umetanje novog elementa u ve sortirani niz elemenata
Najpre emo posmatrati jednostavnu verziju takvog
algoritma (insertion sort) gde se osnovni korak umetanja
ponavlja dovoljni broj puta
Potom emo posmatrati sloeniju, ali bru, verziju
algoritma (Shell sort) koja se dobiva viestrukom
primenom jednostavne verzije
Jednostavno sortiranje
umetanjem (insertion sort)
U nekom trenutku rada algoritma, poetni deo polja je
ve sortiran, a ostatak polja nije sortiran
U jednom prolasku algoritam uzima prvi element iz
nesortiranog dela, te ga umetne na pravo mesto (u
smislu sortiranog redosleda) u sortirani deo, pri emu
dolazi do pomeranja nekih elemenata za jedno mesto
dalje
Dakle, sa jednim prolaskom duina poetnog sortiranog
dela se povea za 1, a duina nesortiranog dela se
smanji za 1.
Jednostavno sortiranje umetanjem
(insertion sort)

Jednostavno sortiranje
umetanjem (insertion sort)
Funkcija insertionSort() u jeziku C implementira jednostavno
sortiranje umetanjem (insertion sort)
Funkcija kao argument prima celobrojno polje a[ ] koje treba sortirati
i njegovu duinu n
void insertionSort (int a[], int n) {
int i, j;
int aux;
for (i = 1; i < n; i++) {
aux = a[i];
for (j = i; j >= 1 && a[j-1] > aux; j--)
a[j] = a[j-1];
a[j] = aux;
}
}
Insertion sort : analiza
vremenske sloenosti
U k-tom prolasku unazad prolazimo sortiranim delom
polja duine k
Zateene elemente pomeraamo za jedno mesto udesno
dok god su oni vei od elementa kojeg elimo umetnuti
na pravo mesto. To u najgorem sluaju daje k
poreenja i otprilike isto toliko pridruivanja.
Dakle, ukupni broj operacija u najgorem sluaju je
otprilike
2 1 + 2 2 + + 2(n 1) = n(n 1).
Red veliine za vreme izvoenja je opet O(n2)
Ovaj algoritam se u praksi ipak pokazuje bri od ranije
opisanih algoritama sa zamenom elemenata
Viestruko sortiranje umetanjem
(Shell sort)
Za zadato k posmatra se k razliitih potpolja sastavljenih
od elemenata originalnog polja, pri emu se elementi u
potpolju meusobno udaljena, u odnosu na originalno
polje, za tano k mesta.
Preciznije, za zadato k posmatraju se potpolja:
P0 : a[0], a[k], a[2k], ...
P1 : a[1], a[k + 1], a[2k+ 1], ...
...
...
Pk1 : a[k 1], a[2k 1], a[3k 1], ...
Viestruko sortiranje umetanjem
(Shell sort)
Proces k-struke primene jednostavnog sortiranja
umetanjem (insertion sort-a) u svrhu zasebnog sortiranja
svakog od ovih k potpolja zove se ksubsort.
Algoritam viestrukog sortiranja umetanjem (shell sort)
radi tako da za definisani opadajui niz k1 > k2 > >
km = 1 obavi k1subsort, zatim k2subsort, . . . , na
kraju km-subsort.
Primetimo da poslednji km-subsort (ustvari 1subsort)
izvodi obini insertion sort na celom originalnom polju
Prethodni k-subsortovi slue zato da (radei nad kratkim
potpoljima) donekle urede celo polje tako da idui k-
subsortovi imaju sve manje posla
Viestruko sortiranje umetanjem
(Shell sort)

Viestruko sortiranje umetanjem
(Shell sort)
Implementacija viestrukog sortiranja umetanjem (Shell
sort-a) u jeziku C dobiva se nadgradnjom ranije
implementacije jednostavnog sortiranja umetanjem
Potrebno je dodati jo jednu petlju koja odgovara
odabranom nizu k-subsortova
Sledea funkcija ShellSort( ) koristi niz k-ova oblika

k1 = n/2, k2 = n/4, . . . , km = 1.
Viestruko sortiranje umetanjem
(Shell sort)
void ShellSort (int a[], int n) {
int i, j, step;
int aux;
for (step = n/2; step > 0; step /= 2) {
for (i = step; i < n; i++) {
aux = a[i];
for (j = i; j >= step && a[j-step] > aux; j -= step)
a[j] = a[j-step];
a[j] = aux;
}
}
}
Shell sort : analiza vremenske
sloenosti
Algoritam viestrukog sortiranja umetanjem
(Shell sort) predstavlja nepoznanicu i tvrd orah
za istraivae
Naime, za razliku od drugih algoritama, za taj
algoritam jo uvek ne postoje jasne i celovite
ocene vremenske sloenosti!
Eksperimentalna merenja pokazuju da je
algoritam iznenaujue brz, u svakom sluaju
bri nego to pokazuju raspoloive ocene
sloenosti
Rekurzivni algoritmi za sortiranje
Rekurzivni algoritme za sortiranje su
algoritmi koji u svrhu sortiranja polja
pozivaju sami sebe
Opisaemo dva takva algoritma:
sortiranje pomou meanja (merge
sort), i
brzo sortiranje (quick sort).
Rekurzivni algoritmi za sortiranje
Prvo emo dati postupak meanja sortiranih polja koji se
pojavljuje kao osnovni korak u algoritmu sortiranja
meanjem
Slinost dvaju razmatranih rekurzivnih algoritama
sortiranja je u tome to oba dele zadato polje na dva
manja polja, zatim rekurzivnim pozivima sortiraju ta dva
manja polja, te na kraju spajaju ta dva manja sortirana
polja u jedno sortirano polje
Razlika je u nainu deljenja velikog polja na manja polja,
te u nainu spajanja manjih polja u vee
Zahvaljujui tim razlikama, dva rekurzivna algoritma
imaju drukije osobine u pogledu vremenske sloenosti
Meanje sortiranih polja (merge)
Pomoni problem vezan s problemom rekurzivnog sortiranja.
Zadata su dva polja sortirana u rastuem poretku:
a[ ] duine n, i b[ ] duine m.
Ta dva polja treba na to jednostavniji nain prepisati u tree polje
c[ ] duine n +m, a koje je opet sortirano u rastuem poretku
Postupak meanja (merge) ide ovako. Simultano itamo a[ ] i b[ ] od
poetka do kraja, te istovremeno prepisujemo proitane elemente u
c[ ]
Dakle, pamtimo kursor tekueg elementa u polju a[ ], odnosno b[ ],
te kursor na prvo slobodno mjesto u c[ ]. Imajui u vidu vrednosti
kursora, uporeujemo vrednosti elemenata u a[ ] i b[ ].

Meanje sortiranih polja (merge)
Ako je jedan od tih tekuih elemenata manji, tada ga
prepiemo u c[ ] te poveamo vrednost odgovarajuih
kursora a[ ], odnosno b[ ].
Ako su tekui elementi jednaki, oba prepiemo u c[ ], te
poveamo oba kursora za 1 na a[ ] i na b[ ].
Kod svakog prepisivanja poveavamo vrednost kursora
c[ ].
Kad jedno od polja a[ ] i b[ ] proitamo do kraja, tada
ostatak drugog polja izravno prepiemo u c[ ].
Meanje sortiranih polja (merge)

Meanje sortiranih polja (merge)
Postupak meanja (merge) je implementiran u jeziku C
kao funkcija merge( ),koja pretpostavlja da su polja a[ ],
b[ ] i c[ ] ustvari samo delovi nekog jo veeg polja p[ ]
Pritom a[ ] odgovara elementima od p[ ] s indeksima
izmeu l i k-1, a b[ ] odgovara elementima od p[ ] s
indeksima izmedu k i r.
Nakon meanja, c[ ] e zauzimati isti fiziki prostor, dakle
deo od p[ ] s rasponom indeksa izmedu l i r.
Kao privremeni radni prostor, funkcija koristi pomono
polje aux[ ]
Polazni delovi polja p[ ] moraju biti sortirani !
Meanje sortiranih polja (merge)
void merge (int p[], int aux[], int l, int k, int r) {
int i, k1, count, aux;
k1 = k-1; /* indeks kraja prvog malog polja */
k2 = l; /* kursor za pisanje u veliko polje */
count = r-l+1; /* broj elemenata u velikom polju */
while (l <= k1 && k <= r) { /* glavna petlja za mesanje */
if (p[l] <= p[k])
aux[k2++] = p[l++];
else
aux[k2++] = p[k++];
}
while (l <= k1) /* Kopiraj ostatak prvog malog polja */
aux[k2++] = p[l++];
while (k <= r) /* Kopiraj ostatak drugog malog polja */
aux[k2++] = p[k++];
for (i = 0; i < count; i++, r--) /* Kopiraj veliko polje natrag */
p[r] = aux[r];
}
Merge : analiza vremenske
sloenosti
Analiza vremenske sloenosti algoritma
meanja(merge) glasi ovako.
Oito je da je vreme izvravanja algoritma
proporcionalno sa zbrojem duina zadatih
polja odnosno s duinom rezultirajueg
polja
Dakle, sloenost iznosi O(n +m).
Sortiranje meanjem (merge
sort)
Re je o sledeem rekurzivnom algoritmu:
Ukoliko se zadato polje sastoji samo od 1
elementa, tada je ve sortirano, inae se
zadato polje deli na dva podjednako manja
polja
Dva manja polja zasebno se sortiraju
rekurzivnim pozivima istog algoritma
Sortirana manja polja se meaju u jedno
sortirano polje uz pomo prethodno opisanog
postupka meanja (merge).
Sortiranje meanjem (merge sort)

Sortiranje meanjem (merge
sort)
Algoritam sortiranja meanjem (merge sort)
implementiran je u jeziku C kao funkcija mergeSort( )
Re je o funkciji koja ostvaruje algoritam pozivajui samu
sebe i funkciju za meanje merge( )
Da bi sortirao polje a[ ] duine n, glavni program mora
najpre alocirati pomono polje aux[ ] iste duine, te zatim
pozvati mergeSort( ) sa sljedeim argumentima:
mergeSort(a, aux, 0, n-1).
Sortiranje meanjem (merge
sort)
void mergeSort (int a[], int aux[], int left, int right) {
int mid;
if (left < right) {
mid = (left + right) / 2;
mergeSort (a, aux, left, mid);
mergeSort (a, aux, mid+1, right);
merge (a, aux, left, mid+1, right);
}
}
Merge sort: analiza vremenske
sloenosti
Svaki rekurzivni poziv algoritma ima vreme raunanja
proporcionalno duini rezultirajueg (meanog) polja
kojeg e on proizvesti.
Skup svih rekurzivnih poziva koji nastaju pri reavanju
polaznog problema moe se prikazati binarnim stablom,
kao na prethodnoj slici sa primerom sortiranja
meanjem
Kad gledamo sve rekurzivne pozive na istom nivou
stabla, primeujemo da oni rade s poljima iji je zbir
duina jednak duini polaznog polja n.
Dakle, zbir vremena raunanja za sve rekurzivne pozive
na istom nivou je O(n).

Merge sort: analiza vremenske
sloenosti
Budui da takvih nivoa ima log
2
n + 1, ukupna
vremenska sloenost algoritma u najgorem sluaju je
(log
2
n + 1) O(n) = O(n log n).
Zahvaljujui ovakvoj oceni u najgorem sluaju, re je o
jednom od najbrih poznatih algoritama za sortiranje
Prednost u odnosu na druge brze algoritme je
mogunost sortiranja velikih polja (datoteka)
uskladitenih na spoljnoj memoriji raunara
Nedostatk u odnosu na druge brze algoritme je dodatni
utroak memorije potreban zbog prepisivanja polja
tokom meanja
Brzo sortiranje (quick sort)
Opet je re o rekurzivnom algoritmu za sortiranje
Odabere se jedan element u polju, takozvani stoer
Svi ostali elementi razvrstaju se ispred (levo od)
odnosno iza (desno od) stoera zavisno od toga da li su
> =ili < =od stoera

Brzo sortiranje (quick sort)
Oigledno, nakon ovakvog razvrstavanja stoer se nalazi na svom
konanom mjestu u smislu traenog sortiranog poretka
Da bi se polje sortiralo do kraja, dovoljno je zasebno (nezavisno)
sortirati potpolje levo, odnosno desno, od stozera
Sortiranje potpolja postie se rekurzivnim pozivima istog algoritma,
ili na trivijalni nain za potpolje duine 0 ili 1.

Brzo sortiranje (quick sort)
Samo razvrstavanje elemenata levo odnosno desno od
stoera efikasno se obavlja u skladu sa prethodnom
slikom, tako da pomiemo kursor s levog odnosno
desnog kraja polja, sve dok su tekui elementi <
odnosno > od stoera
Kad se oba kursora zaustave, nali smo element sleva
koji je > od stoera i element s desna koji je < od stoera
Ta dva elementa na krivim stranama meusobno
zamenimo i zatim nastavimo s pomicanjem kursora
Razvrstavanje je zavreno kad se kazaljke ukrste.
Brzo sortiranje (quick sort)

ALGORITMI I STRUKTURE
PODATAKA
- ALGORITMI ZA SORTIRANJE -


Prof. Duan Starevi

You might also like