PROGRAMIRANJE II P04 Sortiranje doc dr Draen Branin
PROGRAMIRANJE II P-04: Sortiranje doc. dr Dražen Brđanin 2014/15
P-04: Sortiranje n Sadržaj predavanja n Osnovni pojmovi i klasifikacije n Najznačajniji algoritmi za sortiranje n n metode selekcije: Select(ion)-sort umetanja: Insert(ion)-sort, Shell-sort zamjene: Bubble-sort, Quick-sort spajanja: Merge-sort
Osnovni pojmovi o sortiranju n n SORTIRANJE = preuređivanje rasporeda elemenata kolekcije podataka prema nekom kriterijumu n polazna kolekcija (niz) nije uređena = podaci se nalaze u neuređenom poretku n ciljna kolekcija (niz) je uređena = podaci se nalaze u uređenom poretku Ciljni poredak (raspored): n rastući (eng. ascending): n n n strogo rastući: niz[i] < niz[i+1] monotono rastući (neopadajući): niz[i] niz[i+1] opadajući (eng. descending) n n strogo opadajući: niz[i] > niz[i+1] monotono opadajući (nerastući): niz[i] ≥ niz[i+1] n Sortiranje je veoma česta aktivnost n Ciljevi sortiranja: n efikasnije pretraživanje (pronalaženje željenog podatka u kolekciji) n jednostavnija provjera jednakosti kolekcija n sistematizovan prikaz sadržaja kolekcije (rangiranje elemenata)
Klasifikacije tehnika za sortiranje n n Klasifikacija sortiranja prema mjestu sortiranja: n unutrašnje: sortiranje podataka koji se nalaze u operativnoj memoriji (sortiranje nizova i lista) n spoljašnje: sortiranje podataka koji se nalaze na diskovima (sortiranje datoteka) Klasifikacija sortiranja prema načinu manipulacije podacima n direktno n sortiranje se radi direktno na kolekciji – vrši se promjena rasporeda elemenata u polaznoj kolekciji polazna kolekcija rezultat sortiranja ključ: niz[0] niz[1] niz[2] niz[3] info 80 60 90 70 info 60 70 80 90 niz[0] niz[1] niz[2] niz[3] indirektno ne vrši se promjena rasporeda elemenata u polaznoj kolekciji, nego se formira uređena kolekcija pokazivača/indeksa (kad veličina podataka u kolekciji nije zanemarljiva) polazna kolekcija rezultat sortiranja ključ: niz[0] niz[1] niz[2] niz[3] info 80 60 90 70 60 70 80 90 pok[0] pok[1] pok[2] pok[3] pok: ključ:
Unutrašnje sortiranje n Svi podaci nalaze se u operativnoj memoriji. n Primjenjuje se za sortiranje nizova i lista (povezane dinamičke strukture podataka). n Indikatori performanse: n n broj koraka n broj poređenja ključeva n broj premještanja ključeva Sortiranje poređenjem (tehnike zasnovane na poređenju ključeva): n metode selekcije: Select(ion)-sort n n metode umetanja: Insert(ion)-sort, Shell-sort n n po jedan element iz neuređenog dijela umeće se u uređeni dio kolekcije metode zamjene: Bubble-sort, Quick-sort n n selektuje se odgovarajući element iz neuređenog dijela kolekcije i stavlja na kraj uređenog dijela zamjena mjesta dva podatka koji nisu u odgovarajućem poretku metode spajanja: Merge-sort n spajanje uređenih kolekcija (prvo u dvojke, pa dvojke u cetvorke, itd)
Metode selekcije Osnovni princip: selektovati odgovarajući element iz neuređenog dijela kolekcije i staviti ga na kraj uređenog dijela n Select(ion)-sort 6 4 1 7 8 5 3 2 polazna kolekcija Osnovna verzija algoritma: 6 4 1 7 8 5 3 2 1. prolaz 1 4 6 7 8 5 3 2 2. prolaz 1 2 6 7 8 5 3 4 3. prolaz 1 2 3 7 8 5 6 4 4. prolaz 1 2 3 4 8 5 6 7 5. prolaz 1 2 3 4 5 8 6 7 6. prolaz 1 2 3 4 5 6 8 7 7. prolaz 1 2 3 4 5 6 7 8 sortirana kolekcija n n pronađi odgovarajući element (najmanji ili najveći u zavisnosti od željenog poretka) i zamijeni ga sa prvim u kolekciji nastavi proceduru sa preostalim neuređenim dijelom kolekcije sve dok postoji neuređeni dio kolekcije
Metode selekcije Select(ion)-sort n Implementacija: n Spoljašnja petlja određuje granice uređenog dijela kolekcije n Unutrašnja petlja služi za pronalaženje odgovarajućeg elementa u neuređenom dijelu kolekcije void Selection. Sort (<tip> niz[], int n) { int i, j, min; for (i=0; i<n-1; i++) { for (min=i, j=i+1; j<n; j++) if (niz[j]<niz[min]) min=j; n-i poređenja if (min!=i) { <tip> pom=niz[i]; niz[i]=niz[min]; niz[min]=pom; } } } n-1 prolaza
Metode selekcije Select(ion)-sort n Analiza izvršavanja: n Procjena broja operacija potrebnih za sortiranje kolekcije sa n elemenata kvadratna složenost algoritma n n n U ukupnom broju operacija najviše učestvuju poređenja (∼n 2/2) Brzina izvršavanja ne zavisi mnogo od inicijalnog rasporeda (gotovo da je svejedno da li je inicijalni poredak blizak konačnom poretku) Moguće ubrzanje: istovremeno sortiranje sa oba kraja
Metode umetanja Osnovni princip: po jedan element iz neuređenog dijela kolekcije umeće se na odgovarajuće mjesto u uređenom dijelu kolekcije Insert(ion)-sort n Osnovna verzija algoritma: n u svakom koraku prvi element iz nesortiranog dijela kolekcije ubaci na odgovarajuće mjesto u sortiranom dijelu sortirani dio <=x >x x <=x x >x sortirani dio nesortirani dio Ostali elementi nesortirani dio Uobičajeno se karte sortiraju na ovaj način! 6 4 1 7 8 5 3 2 polazna kolekcija 6 4 1 7 8 5 3 2 1. prolaz 4 6 1 7 8 5 3 2 2. prolaz 1 4 6 7 8 5 3 2 3. prolaz 1 4 6 7 8 5 3 2 4. prolaz 1 4 6 7 8 5 3 2 5. prolaz 1 4 5 6 7 8 3 2 6. prolaz 1 3 4 5 6 7 8 2 7. prolaz 1 2 3 4 5 6 7 8 sortirana kolekcija
Metode umetanja Insert(ion)-sort n Implementacija: n n Spoljašnja petlja određuje granice neuređenog dijela kolekcije (uzima redom element po element iz neuređenog dijela kolekcije) Unutrašnja petlja služi za umetanje elementa iz neuređenog dijela na odgovarajuću poziciju u uređenom dijelu i šiftovanje ostatka uređenog dijela kolekcije void Insertion. Sort (<tip> niz[], int n) { int i, j; for (i=1; i<n; i++) { <tip> x=niz[i]; for (j=i; j>0 && x<niz[j-1]; j--) niz[j]=niz[j-1]; niz[j]=x; } } max. i šiftovanja n-1 prolaza
Metode umetanja Insert(ion)-sort n Analiza izvršavanja: n Procjena broja operacija potrebnih za sortiranje kolekcije sa n elemenata n jedan prolaz (poređenje + šiftovanje) n ukupno operacija (poređenje + šiftovanje) kvadratna složenost algoritma n Što je inicijalni raspored bliži željenom poretku, to je sortiranje brže! n Najbolji slučaj: inicijalni raspored je u odgovarajućem poretku (već sortiran niz) n Najgori slučaj: inicijalni raspored je u obrnutom poretku (obrnuto sortiran niz) n Insertion-sort je veoma povoljan za male i skoro uređene nizove!
Metode umetanja Shell-sort n modifikovani (poboljšani) Insertion-sort (autor: Donald Shell) n pripada grupi algoritama za brzo sortiranje n osnovna ideja algoritma: n n u prvom prolazu kroz niz porede se (i po potrebi zamjenjuju) ekvidistantni elementi – npr. elementi razmaknuti za h=n/2 (npr. n=8 h=4 5 1, 6 2, . . . ) u svakom narednom prolazu distanca se smanjuje (npr. h=h/2) i postupak nastavlja sve dok je h≥ 1 h=n/2=8/2=4 6 6 4 4 1 1 7 7 7 2 8 8 5 5 h=h/2=4/2=2 3 3 2 2 2 7 1 1 1 4 2 2 2 6 6 3 3 2 4 4 4 8 8 6 6 5 5 5 h=h/2=2/2=1 3 3 8 8 7 7 7 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 6 6 5 5 5 5 6 6 6 8 8 8 7 7 7 7 8
Metode umetanja Shell-sort n Implementacija: void Shell. Sort (<tip> niz[], int n) { int i, j, h; for (h=n/2; h>0; h/=2) { for (i=h; i<n; i++) { <tip> x=niz[i]; Efikasnost algoritma zavisi od izabrane sekvence za h Najgori slučaj Hibbard-ova sekvenca (2 k-1, . . . , 7, 3, 1) Najgori slučaj for (j=i; j>=h && x<niz[j-h]; j-=h) niz[j]=niz[j-h]; niz[j]=x; } } } Sedgwick (. . . , 109, 41 , 19, 5, 1) Najgori slučaj
Metode zamjene Osnovni princip: zamjena dva elementa koji nisu u odgovarajućem poretku Bubble-sort (direktna zamjena) n Osnovna ideja: zamjena svaka dva susjedna elementa koji nisu u odgovarajućem poretku n n kreni od početka kolekcije prema kraju zamijeni svaka dva susjedna elementa koji nisu u uređenom poretku u jednom prolazu kroz kolekciju najlakši (najteži) “ispliva na površinu” (na početak uređenog dijela kolekcije) optimizacija: ako nije bilo zamjena, sortiranje je završeno 1. prolaz 2. prolaz 3. prolaz 4. prolaz 5. prolaz 6417532 4617532 4167532 4165732 4165372 4165327 1465327 1456327 1453627 1453267 1435267 1432567 1342567 1324567 1234567
Metode zamjene Bubble-sort n Implementacija: void Bubble. Sort (<tip> niz[], int n) { int i, j; for (i=0; i<n-1; i++) { for (j=0; j<n-i-1; j++) if (niz[j]>niz[j+1]) { <tip> pom=niz[j]; niz[j]=niz[j+1]; niz[j+1]=pom; } } } max. n-i poređenja i zamjena n-1 prolaza
Metode zamjene Bubble-sort n Analiza izvršavanja: n Procjena broja operacija potrebnih za sortiranje kolekcije sa n elemenata n jedan prolaz (poređenje + zamjena) n ukupno operacija za n-1 prolaza kvadratna složenost algoritma n Što je inicijalni raspored bliži željenom poretku, to je sortiranje brže! n Najbolji slučaj: inicijalni raspored je u odgovarajućem poretku (već sortiran niz) n Najgori slučaj: inicijalni raspored je u obrnutom poretku (obrnuto sortiran niz) n Veći podaci na početku niza brzo idu prema kraju (nije problem) – “zečevi” n Manji podaci na kraju niza sporo idu prema početku (veći problem) – “kornjače”
Metode zamjene Quick-sort n Rekurzivni algoritam: “divide-and-conquer” (lat. “divide et impera”) “podijeli pa osvoji”/ “zavadi pa vladaj” n Osnovna ideja n n n osnovni slučaj: broj elemenata u kolekciji 0 ili 1 prekini izvršavanje izaberi razdvojni element (pivot) u kolekciji rasporedi ostale elemente iz kolekcije u dva podskupa manji= {x niz{pivot} | x pivot} veći = {x niz{pivot} | x≥pivot} vrati sortirani niz: { Quick. Sort(manji), pivot, Quick. Sort(veći) } Izbor pivota: n n nije jedinstveno određen – pivot može da se bira na različite načine implementacija u ovom slučaju traži sve veće od početnog elementa u nizu (uzet za pivota) sa lijeve strane i mijenja ih sa svim manjim od pivota sa desne strane, kad se sretnu granice tu se postavi pivot
Metode zamjene Quick-sort n Implementacija: void q. Sort(int niz[], int begin, int end) { if (begin < end) { int pivot = split(niz, begin, end); q. Sort(niz, begin, pivot-1); q. Sort(niz, pivot+1, end); } } Prosječna složenost: linearnologaritmaska Najgori slučaj: kvadratna složenost int split(int niz[], int begin, int end) { int i=begin, j=end; int pivot = niz[begin]; while (i<j) { while (niz[i]<=pivot && i<j) i++; while (niz[j]>pivot) j--; if (i<j) { int pom=niz[i]; niz[i]=niz[j]; niz[j]=pom; } } niz[begin] = niz[j]; niz[j] = pivot; return j; }
Metode zamjene Quick-sort (ilustracija izvršavanja) 6 4 1 7 5 3 i 6 j 4 1 7 5 3 i 6 4 1 2 3 4 4 1 1 2 2 2 traži prvog većeg od početka niza i prvog manjeg od kraja niza zamjena prvog većeg i posljednjeg manjeg j 5 3 i 6 2 5 5 7 j 3 7 j i 6 7 nastavi traženje sljedećeg većeg od početka i sljedećeg manjeg i i j su se sreli/mimiošli pa se vrši zamjena pivota i j-tog elementa nova pozicija pivota, lijevo su svi manji, desno su svi veći pivot q. Sort(niz, begin, pivot-1) q. Sort(niz, pivot+1, end) ova particija je već sortirana, jer ima samo jedan element
Metode zamjene Quick-sort (ilustracija izvršavanja) 3 4 1 2 i 3 j 4 1 i 3 2 1 2 2 2 5 j 1 i 3 5 4 5 j 1 4 j i 3 4 pivot 5 5 traži prvog većeg od početka i prvog manjeg od kraja zamjena prvog većeg i posljednjeg manjeg nastavi traženje sljedećeg većeg i sljedećeg manjeg i i j su se sreli/mimiošli pa se vrši zamjena pivota i j-tog elementa nova pozicija pivota, lijevo su manji, desno su veći 1 2 i 1 j 2 j 1 i 2 i i j su se sreli/mimiošli pa se vrši zamjena pivota i j-tog elementa jedinična (sortirana) particija pivot 4 5 i 4 j 5 j 4 i 5 pivot traži prvog većeg od početka i prvog manjeg od kraja jedinična (sortirana) particija
Metode spajanja Osnovni princip: spajanje uređenih kolekcija u jednu uređenu kolekciju Merge-sort (John von Neuman, 1945) n Rekurzivni algoritam: “divide-and-conquer” n Osnovna ideja n n n Nesortirana kolekcija se podijeli na dva (pod)jednaka dijela Svaki dio se dalje dijeli, dok se ne dođe do jedinične kolekcije (jedinična kolekcija je sortirana) Dvije sortirane kolekcije spajaju se u jednu sortiranu kolekciju 6 6 4 4 4 1 4 6 1 8 5 1 7 2 3 8 7 1 4 7 7 1 4 6 1 1 8 7 3 5 5 3 5 6 8 2 7 2 3 5 5 4 2 3 3 5 8 2 2 3
Metode spajanja Merge-sort n Implementacija: void merge. Sort(int niz[], int begin, int end) { if (begin<end) { int sredina = (begin + end)/2; int i, j, k, len=end-begin+1; int pom[len]; merge. Sort(niz, begin, sredina); merge. Sort(niz, sredina+1, end); /* spajanje */ i=begin; j=sredina+1; k=0; while (i<=sredina && j<=end) pom[k++] = (niz[i]<=niz[j]) ? niz[i++] : niz[j++]; while (i<=sredina) pom[k++]=niz[i++]; while (j<=end) pom[k++]=niz[j++]; for (i=0; i<len; i++) niz[begin+i] = pom[i]; } } Prosječna složenost i najgori slučaj: linearnologaritmaska Efikasnost algoritma ne zavisi od inicijalnog rasporeda! Potrebna pomoćna kolekcija.
Poređenje algoritama kvadratne složenosti Bubble 800 700 seconds 600 Selection 500 400 Insertion 300 200 Shell 100 0 10 10000 n 250000 75000 100000
Poređenje Merge- i Quick-sort algoritama 0, 8 0, 7 seconds 0, 6 Merge 0, 5 0, 4 Quick 0, 3 0, 2 0, 1 0 10 10000 n 250000 75000 100000
- Slides: 24