Cuprins:
1. Definirea sortarii prin ansamble (heapsort).
2. Varinate ale sortarii prin ansamble.
3. O comparatie a algoritmului de sortare prin
ansamble cu alte metode de sortare.
4. Pseudocodul algoritmului de sortare prin
ansamble exprimat in limabjul Pascal.
5. Un exemplu complet de algoritm de sortare prin
ansamble.
1. Definirea sortarii prin ansamble. >>>
Sortarea prin ansamble (sau "heapsort") este unul dintre cei mai buni algoritmi de sortare,
de comparare si face parte din familia algoritmilor de sortare prin selectie.Desi
are o performanta mai scazuta decat cele mai bune implementari ale sortarii
rapide, el are totusi avantajul de a realiza o sotare dificila intr-un timp
de O(n logn).Sortarea prin ansamble este un algoritm de sortare
"pe loc" si nu este un algoritm de sortare stabil.
Un mod simplu de a sorta o lista de elemente este utlilizarea structurii
de date numita heap (in traducere inseamna "gramada ordonata").Adica toate
elementele care trebuiesc sortate sunt inserata intr-o gramada ordonata de
elemente, si aceasta gramada ordonata de elemente este organizata in asa
mod incat fiecare dintre elementele cu valori mari (se adauga in gramada elementelor
cu valori mari) iar elementele cu valori mai mici (se adauga in gramada elementelor
cu valori mici) pentru ca ele sa fie usor de extras.Oricum, acest mod de
aranjare a elementelor aranjeaza structura gramezii de elemente ordonate,
aceste elemente cu valori mici sau mari pot fi extrase in mod repetat pana
cand nu mai ramane nici un element in gramada.Extragerea elementelor se realizeaza
in ordinea elementelor.
Daca se utlilizeaza acest mod de sortare atunci va fi necesara prezenta
unui spatiu suplimentar de memorie pentru a stoca elementele grupate ordonat
(heap).Un alt mod de a stoca eficient o grupare ordonata de elemente este
utlilizarea stocarii binare (sau stocarea alternativa, adica sa se stocheze
o gramada de elemente ordonate a carui structura (arbore) sa aiba mai mult
de doi fii) in cadrul unui tablou de intrare care nu este inca sortat.Sortarea
prin ansamble efectueaza doua operatii de baza asupra structurii arborelui
al elementelor grupa ordonat: insertia si suprimarea nodului radacina.De
fiecare data se va suprima (extrage) elementul cu cea mai mare valoare din
gramada, apoi acesta se va pozitiona in ultimul loc al tabloului care nu
este ocupata, si se utilizeaza acest principiu si pentru elementele ramase
nesortate din tablou:
Grupul elementelor ce trebuiesc sortate |
Elemente sortate |
|
|
2. Variante ale sortarii prin ansamble. >>>
* Cea mai importanta varianta a unui algoritm simplu de sortare prin
ansamble a fost improvizat de catre R.W.Floyd care in practica este cu 25%
mai rapid deoarece foloseste numai o comparatie la fiecare adaugare a unui
element in gramada de elemente ordonate urmata apoi de stergerea nodului
radacina (principal) pentru nodul-fiu nou adaugat.Astfel aceasta versiune
de sortare prin ansamble lucreaza mult mai usor, caci metoda originala a
sortarii prin anamble realizeaza o localizare crescatoare a elementelor.Astfel
ca metoda lui R.W.Floyd incepe sortarea de la adresa elementului care a fost
inlocuit, astfel ca algoritmul care functiioneaza dupa acest principiu va
avea +/-1 contrabalansari in codul de implementare.
* O alta varianta a sortarii prin ansamble mai putin cunoscuta este sortare
ternara prin ansamble care utlilizeaza o grupare termnara de elemente ordonate
intr-un gup binar de elemente ordonate, adica fiecare element din gramada
va avea teri fii.Sortarea elementelor ternare este mult mai complexa de programat
insa este mult mai rapida, caci fiecare pas al metodei de inlocuire efectueaza
trei comparatii apoi elementele sunt aranjate intr-o singur grup ternar
ordonat de elemente, iar daca se utilizeaza un grup de elemente binare vor
fi necesare doua comparatii pentru fiecare element care vor pi stocate intr-un
griup de elemente ordonate.Sortarea elementelor ternare poate efectua doua
comparatii intr-un timp mult mai scurt decat se compara trei elemente binare
, insa aceste doua comparatii ale sortarii ternare multiplica numarul de
noduri ale arborelui elementelor ternare cu un factor de 9, care este mai
mult decat factorul de 8 pe care il detine arborele elementelor binare.Oricum,
chiar daca sortarea ternara este mai greu de programat, ea este cu 12% mai
rapida decat cea mai simpla varianta a sortarii prin ansamble.
* Algoritmul de sortare smoothsort (in taducere inseamna "sortarea
in plan") este o alta varianta a sortarii prin ansamble descoperit de catre
Edser Dijkstra in anul 1981.Aceasta varianta de sortare are si ea limita
timpului de sortare de finit prin relatia O(n log n).Avantajul
sortarii in plan este ca realizeaza un timp de sortare apropiat de limita
de timnp definita prin realatia O(n) daca elementele ce trebuiesc sortare
sunt sortare partial, iar sortarea prin ansable in acest caz realizeaza o
limita a timpului de sortare definita prin realatia O(n log n).Sortarea
in plan este rar utilizata deoarece prezinta un algoritm complex.
3. O comparatie a metodei de sortare prin ansamble cu
alte metode de sortare. >>>
Sortarea pri ansamble ar putea concura cu sortarea rapida, care este un algoritm
de sortare foarte eficient, si care este bazat pe procedeul de comparare
a elementelor.
Sortarea rapida (quicksort) este tipic mult mai rapida deoarece poate
accesa date stocate in memoria CACHE de unde se desprind si alte avantaje,
insa timpul de sortare pentru acesta sortare rapida in cazul in care se comporta
ineficient este de O(n2), care este inacceptabil daca se
lucreaza cu lista mari de date, aceasta se poate intampla si daca nu se cunoaste
foarte bina algoritmul de implementare, rezultand uneori si un risc de securitate.
Algoritmul de sortare rapida necesita un spatiu de memorie suplimantar
care are un numar de Ω(log n) locatii, acasta insemnand ca nu este
un algoritmde sortare "pe loc".Aceasta in general nu reprezinta un dezavantaj,
insa poate fi in cazul in care este folosita in cadrul sistemelor bazate
pe microprocesoare sau microcontrlolere unde daca alocarea memoriei este
restrictionata.Este posibila si crearea de algoritmi de sortare rapida care
sa utilizeze un spatiu de memorie care sa aiba in pemanent acelasi nu ar
de locatii, insa aceasta este foarte rar utilizat in practica deoarece este
un algoritm complex.
Sortarea prin ansamble este utilizata in carul sistemelor bazate pe microprocesoare
sau microcontrolere care sunt restrictionate in rularea in timp real sau
au restrictionat si spatiul de memorie alocat, ori sistemele trebuie sa aiba
un grad mare de secutitate, deoarece realizeaza o limita a timpului in de
sortare definit prin relatia O(n log n) avant si avantajul
utliliozari unui spatiu auziliar de memorie constant.
Soartarea prin ansamble mai poate concura si cu sortarea prin interclasare,
care este o metoda de sortare ce are aceasi limita a timpului de sortare
ca si sortaea prin ansamble, insa sortarea prin interclasare necesita un spatiu
de memorie suplimentara de Ω(n) locatii, insa sortarea prin ansamble utilizeaza
un spatiu constant de memorie.Un alt avantaj al sortarii prin ansambel in
comparatie cu sortarea prin inerclasare este ca se poate comporta eficient
in practica, in cazul in care se utilizeaza echipamente mici si greu accesibile
din memoria CACHE.Intr-o alta ordine de idei putem constata ca sortarea prin
interclasare a re mai multe avantaje decat sortarea prin ansamble:
* Asemanator cu sortarea rapida, sortarea prin interclasare realizeaza
o sortare rapida a elementelor greu accesibile din memoria CACHE, fiind astfel
mult mai performante decat sortarea prin ansamble, deoarece acestea acceseaza
elementele in ordinea in care sunt localizate.
* sortarea prin interclasare este o sortare stabila.
* Sortarea prin interclasare poate sorta in paralel, fara ca procesele
de sortare sa depinda unele de altele, realizand astfel un timp de sortare
liniar, insa acest concept nu poate fi pentru sortarea prin ansamble.
* Sortarea prin interclasare poate fi adaptata usor pentru a putea opera
cu liste inlantuite sau cu liste de mari dimensiuni stocate pe dispozitive
CD-ROM sau stocate intr-o locatie din retea care sunt accesate foarte lent.Sortarea
prin ansamble se comporte aficient numai daca datele cu care lucreaza pot
fi accesate aleator, insa cum acest tip de sortare prezinta o localizare
a referintelor foarte slab rezulta ca aceasta s-ar comporta foarte ineficient
in cazul in care se lucreaza cu dipozitive care necesita un timp oarecum
mare de acces.
4. Pseudocod pentru sortarea prin ansamble exprimat in
limbajul Pascal. >>>
Exemplul de algoritm prezentat mai jos este reprezinta un "simplu" mod
de a implementa un algoritm de sortare prin ansamble, unde termenul de inlocuieste
este folosit pentru a schimba pozitia pentru doua elemente aflate in tabloul
care se sorteaza.
function sortare_ansamble(a, contor) este inceput: un tablou in care elementele au ordine diferita a de lungime contor ( prima locatie a elementelor cu valori mari) grupeaza(a, contor) capat := contor - 1 while capat > 0 do(inlocuieste radacina (elementeul cu valoarea maxima) grupului cu ultimul element di grup) inlocuieste(a[capat], a[0]) (se scade numarul de elemente din grupul care trebuie sortat cu 1, astfe incat radacina anterioara este pozitionata in locatia protrivita) caapt:= capat - 1 (se aranjeaza descrescator grupul de elemente iarasi dupa ordinea elementelor cu valori mari) aranjeaza_descrescator(a, 0, capat) function grupeaza(a,contor) este(se incape prin a localiza pozitia parintelui ultimului nod din grup) inceput := contor ÷ 2 - 1 while inceput >= 0 do(inlocuieste nodul de la pozitia de la care se porneste sortarea in pozitia potrivita, si se contiuna astfel pentru toate nodurile urmatoaare conform ordinii pozitiilor elementelor din grup) aranjeaza_descrescator(a, inceput, contor-1) inceput := inceput - 1 (astfel radacina pentru toate nodurile si elementele sunt ordonate)/ul>function aranjeaza_descrescator(a, inceput, capat) esteintrare: capat reprezinta pozitia ultimului element din grupul ce trebuie sortat radacina := inceput while radacina * 2 + 1 > = capat do (atat timp cat radacina are un singur fiu)fiu := radacina * 2 + 1 (radacina*2+1 este o referinta pentru fiul din stanga) (Daca fiul mai are un frate si daca valoarea fiului este mai mica decat a fratelui...) if fiu < capat and a[fiu] < a[fiu + 1] thenfiu := fiu + 1 (... atunci fa realizeaza o referinta pentru fiul din dreapta) if a[radacina] < a[fiu] then (se termina procedeul de ordoanre in functie de elementul cu valarea maxima)inlocuieste(a[radacina], a[fiu]) radacina := fiu (se repeta procedeul de aranjarea a alementelor) elsereturn
Functia grupeaza poate fi vazuta ca un procedeu recursiv
de insearare a elementelor din grup intr-o ordine crescatoare.A doua versiune
difera numai prin faptul ca datele se ordoeaza in ordinea in care sunt sortate.Meotoda
de aranjeare de deasupra incepe sortarea de la capatul grupului (adica cu
elementele care pot avea valori mari) si urca pe masura ce elementele sunt
sortate.Urmaotrul algoritm incepe sortarea la inceputul grupului de elemente
si coboara catre capatul grupului pe masura ce elementele sunt sortate in
ordine crescatoare:
function grupeaza(a,contor) este (capat este atribuit pentru elementul aflat pe pozitia prima pozitie, acesta find elementul stang al radacinii (val miinma a grupului)) capat := 1 while capat < contor(aranjeaza cescator referinta aflata la inceputul grupului in locul potrivit, procedand asa si pentru toate nodurile de deasupra aranjeaza_crescator(a, 0, capat) capat := capat + 1 (dupa ce s-a aranjat crescator si ultimul nod, atunci grupul este sortat crescator) function aranjeaza_crescator(a, incput, capat) esteinceput: inceput reprezinta locatia primului element al grupului care trebuie sortat. fiu := capat while fiu > inceputparinte :=[(child - 1) ÷ 2]if a[parinte] < a[fiu] then (se paraseste metoda de sortare in ordinea elementelor cu valori maxime) inlocuieste(a[parinte], a[fiu]) fiu := parinte (se contiunea aranjarea crescatoare incpunad cu un nou nod parinte) else return
5. Exemplu de implementare in limbajul C al algoritmului
de sortare prin ansamble. >>>
#include #include void sortare_ansamble(int[], int); int main() {int i; int a[] = {7,2,10,25,17,23,27,16,19,37,42,4,33,1};//copia tabloului care trebuie sortat int a1[] = {7,2,10,25,17,23,27,16,19,37,42,4,33,1};//tabloul care trebuie sortat for(i=sizeof(a)/sizeof(*a); i>1; i--) {sortare_ansamble(a, i - 1); } printf("Tabloul initial este: "); for(i=0;iprintf("\n"); printf("\nTabloul sortat este: "); for (i = 0; i < sizeof(a)/sizeof(*a); i++) printf(" %d ",a[i]); return; } void sortare_ansamble(int a[], int limita_a) {int i,o; int fiu_stang, fiu_drept, fiu_mijloc, radacina, temp; radacina = (limita_a-1)/2; for(o=radacina;o>=0;o--) {for(i=radacina;i>=0;i--) {fiu_stang = (2*i)+1; fiu_drept = (2*i)+2; if ((fiu_stang <= limita_a) && (fiu_drept <= limita_a)) {if(a[fiu_drept] >= a[fiu_stang]) fiu_mijloc = fiu_drept; else fiu_mijloc = fiu_stang; } else {if(fiu_drept > limita_a) fiu_mijloc = fiu_stang; else fiu_mijloc = fiu_drept; } if (a[i] < a[fiu_mijloc]) {temp = a[i]; a[i] = a[fiu_mijloc]; a[fiu_mijloc] = temp; } } } temp = a[0]; a[0] = a[limita_a]; a[limita_a] = temp; return; }
Exemplu de mai sus va afisa pe ecran:
Tabloul initial este: 7 2 10 25 17 23 27 16 19 37 42 4 33 1 Tabloul sortat este: 1 2 4 7 10 16 17 19 23 25 27 33 37 42 |