Vous êtes sur la page 1sur 70

Sortare si algoritmi de sortare

1. Introducere
Sortarea este o metoda (un algoritm), prin intermediul careia se poate ordona o anumita
clasa de obiecte concrete sau abstracte, dupa unul sau mai multe criterii impuse iar cautarea
este o metoda, prin intermediul careia, se poate cauta, dupa criterii precizate, pentru regasire
un anumit obiect concret sau abstract intr-o multime ordonata sau nu de obiecte concrete sau
abstracte
Ca exemple se pot da :
- sortarea (ordonarea) crescatoare sau descrescatoare a unui sir de numere reale si
cautarea unui numar sau a mai multor numere in acest sir de numere
- sortarea unei liste de persoane in ordinea alfabetica a numelor si prenumelor
acestora si cautarea unei persoane sau a mai multor persoane cu anumite
caracteristici precizate.
- ordonarea unei liste de persoane dupa importanta muncii lor si cautarea unor
persoane dupa criterii precizate.
- ordonarea unei liste de persoane dupa anumite criterii preferentiale si cautarea in
aceasta lista.
etc.
Knuth dedica un volum intreg sortarii si cautarii intr-o multime de obiecte concrete
sau abstracte, intitulat sugestiv Sortare si cautare si care face parte din seria Arta
Programarii Calculatoarelor. Titlul Sortare si cautare poate da impresia ca volumul s-ar
adresa doar programatorilor de sisteme de programme si aplicatii informatice, interesati de
conceperea unor subprograme sau rutine de sortare cu scop general sau de aplicatii de cautare
si regasire a informatiilor. In realitate, domeniul sortarii si cautarii ofera un mijloc ideal
pentru analiza unor game largi de subiecte generale importante :
- cum se pot descoperii algoritmii buni
- cum se pot optimiza algoritmii si programele
- cum se poate analiza matematic eficienta algoritmilor
- cum se poate allege rational cel mai bun dintre algoritmii necesari rezolvarii unei
clase de probleme
- cum se pot aprecia niste algoritmi ca fiind cei mai buni posibili
- cum interactioneaza teoria calculelor matematice cu diverse consideratii practice
- cum se pot utiliza eficient resursele calculatoarelor (memoriile interne si externe
de tipul discurilor magnetice sau optice)
Fiecare aspect important al programarii isi gaseste rezolvarea in contextul sortarii si cautarii.

2. Sortare si algoritmi de sortare
2.1. Definirea problemei sortarii
Fiind date N inregistrari, sa se aranjeze aceste inregistrari in functie de valorea
campului K, numit cheie de sortare, astfel incat intre oricare doua inregistrari vecine R
i
si R
i+1

sa existe una dintre relatiile urmatoare intre cheile de sortare : K
i
< K
i+1
sau K
i
> K
i+1
.
Relatia de ordine < sau > trebuie sa satisfaca urmatoarele conditii :
a. Una si numai una din variantele : a<b, a=b, a>b este adevarata (legea trihotomiei).
b. Daca a<b si b<c, atunci a<c (legea tranzitivitatii).
Caracteristici ale sortarii
Sortare stabila se numeste acea sortare care in urma executarii sale face ca
inregistrarile cu chei egale sa isi pastreze pozitiile relative.
Sortare interna este aceea sortare care pastreaza, pe tot parcursul executarii sale toate
inregistrarile in memoria interna a calculatorului.
Sortare externa este aceea sortare care, din cauza numarului mare de inregistrari, nu
pastreaza, pe tot parcursul executarii sale toate inregistrarile in memoria interna a
calculatorului si foloseste pentru memorare si spatii pe memoriile externe (discuri magnetice,
flexibile, optice, etc.)..
Pentru simplificarea prezentarii problemelor de sortare se vor aplica principalii
algoritmi de sortare asupra unor vectori care contin cheile de sortare iar pentru ca
implementarea lor in C sa fie cat mai fireasca se va considera ca primul element al oricarui
vector ocupa pozitia zero si are, in consecinta, indexul zero.
2.2. Algoritmi de sortare
In functie de obiectivele urmarite pe parcursul ordonarii elementelor unui vector exista mai
multi algoritmi de sortare.
2.2.1. Sortarea cu bule
Algoritmul de sortare cu bule, cunoscut in literartura de specialitate algoritmul Bubble Sort,
este un algoritm usor de implementat, majoritatea studentilor folosindu-l cu predilectie .
Robert Sedgewick propunea eliminarea acestui algoritm din toate cartile despre algoritmi, iar
Knuth preciza ca sortarea cu bule pare sa nu aiba nimic recomandabil, cu exceptia unui
nume care capteaza atentia si a unor parametri al caror studiu conduce la probleme teoretice
interesante.
Algoritmul are la baza definitia unui sir ordonat : Un sir aeste ordonat crescator sau
descrescator daca pentru orice i natural din intervalul [0,n-1] exista proprietatea a
i
< a
i+1
,
respectiv a
i
> a
i+1.


Algoritmul de testare a ordonarii uni vector : Dandu-se un vector v cu n elemente reale sa se
precizeze daca vectorul este ordonat crecator respectiv descrescator.

Descrierea algoritmului in pseudocod :
functie este_sortat (v, n)
inceput
// se initializeaza variabila sortat cu adevarat, considerandu-se apriorii vectorul sortat
sortat = adevarat
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1]
pentru i=0 la n-2 executa
inceput
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta variabila fanion
sortat primeste valoarea fals
daca v[i]>v[i+1] atunci sortat = fals ;
sfarsit
returneaza sortat
sfarsit.

Descrierea algoritmului in C :
bool este_sortat (float v[], int n)
{
// se initializeaza variabila sortat cu adevarat, considerandu-se apriorii vectorul sortat
bool sortat = true
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1]
for (i=0 ; i<n-1 ; i++)
{
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta variabila fanion
sortat primeste valoarea fals
if (v[i]>v[i+1]) sortat = false ;
}
return sortat ;
}

Exemplul 1. Se considera orice vector v cu n elemente reale. Oricare ar fi vectorul furnizat,
utilizandu-se algoritmul de testare sortare cu bule, sa se determine daca, este ordonat
crescator.
#include <iostream.h>
#include <conio.h>
# define nmax 20
bool este_sortat (float v[], int n)
{
// se initializeaza variabila sortat cu adevarat, considerandu-se apriorii vectorul sortat
bool sortat = true;int i;
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1]
for (i=0 ; i<n-1 ; i++)
{
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta variabila fanion
sortat primeste valoarea fals
if (v[i]>v[i+1]) sortat = false ;
}
return sortat ;
}
void main ()
{
float v[100] ; int n,i ;char r='d' ;
while (r=='d')
{
// citirea dimensiunii vectorului
do
{
cout<<"\n dati numarul de componente ale vectorului [0,"<<nmax<<"]=" ;
cin>>n;
}
while ((n<0) || (n>nmax)) ;
// citirea componenteler vectorului
for (i=0 ; i<n ; i++)
{
cout<<"v["<<i<<"]=";
cin>>v[i];
}
// afisarea rezultatului testarii
cout<<"\n vectorul dat:" ;
for (i=0 ; i<n ; i++) cout<<v[i]<<' ' ;
if (este_sortat(v, n))
cout<<"\n vectorul dat este ordonat";
else
cout<<"\n vectorul dat nu este ordonat";
cout<<"\n continuati ?(d/n):";
cin>>r;
}
}

Tehnica prin care se atribuie unei variabile logice valoarea true sau false, in functie de
anumite conditii intalnite intr-un algoritm, poarta numale de tehnica fanionului. In functia de
testare a ordonarii, variabila fanion, sortat, se initializeaza cu valoarea true (adevarat) ca si
cand elementele vectorului ar fi ordonate crescator. In urma compararii a oricaror doua
elemente vecine ale unui vector pot aparea urmatoare doua posibiltati :
a. Cele doua elemente respecta proprietatea pe care o au elementele unui vector
ordonat. Dintr-o singura comparare nu se poate spune nimic vector in ansamblul
sau.
b. Elementul din stanga nu este mai mic decat vecinul sau din dreapta. In acest caz
se poate afirma cu certitudine ca sirul nu este ordonat.
Ca atare, la intrarea in functie vom presupune ca sirul este apriori ordonat (fanionul
sortat = true). Daca pe parcursul compararii tuturor elementelor vecine, vom gasi cel putin
doua elemente care nu sunt asezate in ordine, atunci se va putea afirma ca presupunerea
initiala a fost falsa si ca vectorul, in ansamblul sau, este neordonat. Daca la finalul compararii
tuturor elementelor vecine variabila fanion sortat va avea aceeasi valoare pe care a primit-o
inainte de parcurgerea vectorului (true), ceea ce implica faptul ca nu s-a gasit nici macar doua
elemente vecine care nu sunt asezate in ordinea ceruta, atunci se va putea spune, cu
certitudine, ca vectorul este ordonat.

Algoritmul de sortare cu bule a unui vector :
Algoritmul de sortare cu bule este, de fapt, o extensie a algoritmului de testare a ordonarii
unui vector. Atunci cand se gasesc doua elemente vecine care nu respecta proprietatea pe care
o au oricare doua elemente vecine dintr-un vector ordonat, pe langa modificarea variabilei
fanion la valoare fals, se va proceda la interschimbarea celor doua elemente intre ele. Daca la
sfarsitul parcurgerii vectorului s-a efectuat cel putin o interschimbare atunci nu se poate
spune cu certitudine ca vectorul este ordonat si va trebui sa se reia procedeul de comparare,
pana cand variabila fanion, dupa o parcurgere completa, va ramane cu valoarea true cu care a
fost initializata inainte de inceperea compararilor, fapt ce ne arata cu certitudine ca nu s-a
efectuat nicio interschimbare si ca vectorul este ordonat.

Descrierea in pseudocod a algoritmului functiei de sortare cu bule
functie sortare_bule (v, n)
inceput
repeta
inceput
// se initializeaza variabila sortat cu adevarat, considerandu-se apriorii vectorul sortat
sortat = adevarat
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1]
pentru i=0 la n-2 executa
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta se interschimba
elementele
// si variabila fanion sortat primeste valoarea fals
daca v[i]>v[i+1] atunci
inceput
aux = v[i]
v[i] = v[i+1]
v[i+1] = v[i]
sortat = fals ;
sfarsit
sfarsit
cat timp (sortat = fals)
sfarsit.

Descrierea algoritmului sortarii cu bule in C :
void sortare_bule (float v[], int n)
{
bool sortat ; int i ; float aux ;
// bucla de testare cu interschimbare
do
{
// se initializeaza variabila sortat cu adevarat, considerandu-se apriorii vectorul sortat
bool sortat = true
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1]
for (i=0 ; i<n-1 ; i++)
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta
// se interschimba elementele intre ele si variabila fanion sortat primeste valoarea
fals
if (v[i]>v[i+1])
{
aux = v[i] ; v[i] = v[i+1] ; v[i+1] = aux ;
sortat = false ;
}
}
while ( !sortat) ;
}

Exemplul 2. Se considera orice vector v cu n elemente reale. Oricare ar fi vectorul furnizat,
sa se ordoneze crescator, utilizandu-se sortarea cu bule

#include <iostream.h>
#include <conio.h>
# define nmax 20
int nr_comparari = 0; //contor nr comparari
int nr_treceri = 0; //contor nr treceri
void sortare_bule (float v[], int n)
{
// declararea variabilelor locale
bool sortat; int i; float aux;
// bucla de comparare a elementelor vecine
do
{
nr_treceri++;//incrementare contor treceri
// se initializeaza variabila sortat cu adevarat, considerandu-se apriorii vectorul sortat
sortat = true;
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1]
for (i=0 ; i<n-1 ; i++)
{
nr_comparari++; //incrementare contor comparari
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta variabila fanion sortat
primeste valoarea fals
if (v[i]>v[i+1])
{
aux = v[i]; v[i] = v[i+1]; v[i+1] = aux;
sortat = false ;
}
}
}
while (!sortat);
}
void main ()
{
float v[100] ; int n,i ;char r='d' ;
while (r=='d')
{
// citirea dimensiunii vectorului
do
{
cout<<"\n dati numarul de componente ale vectorului [0,"<<nmax<<"]=" ;
cin>>n;
}
while ((n<0) || (n>nmax)) ;
// citirea componenteler vectorului
for (i=0 ; i<n ; i++)
{
cout<<"v["<<i<<"]=";
cin>>v[i];
}
// afisarea rezultatului testarii
cout<<"\n vectorul dat:" ;
for (i=0 ; i<n ; i++) cout<<v[i]<<' ' ;
// apelarea functiei de sortare cu bule
sortare_bule (v, n);
cout<<"\n vectorul ordonat:" ;
for (i=0 ; i<n ; i++) cout<<v[i]<<' ' ;
// afisarea numarului de comparari si treceri prin vector
cout<<"\n sortarea s-a facut cu "<<nr_comparari<<" comparari"
<<" si in "<<nr_treceri<<" treceri";
// initializarea numarului de comparari si treceri
nr_comparari = 0;
nr_treceri = 0;
cout<<"\n continuati ?(d/n):";
cin>>r;
}
}
Dandu-se cazul cel mai defavorabil, vectorul v = (5, 4, 3, 2, 1), ordonat descrescator,
pentru ordonarea sa crescatoare s-au efectuat 5 parcurgeri efectuandu-se 20 de comparari, iar
pentru cazul cel mai favorabil, vectorul v = (1, 2, 3, 4, 5), deja ordonat s-au efectuat 1
parcurgere si 4 comparari..
Sa analizam ce se intampla la o parcurgere a elementelor vectorului. Presupinem ca
cel mai mare element se afla pe pozitia j, cu j < n-1. Cand se ajunge sa se compare acest
element cu vecinul sau aflat de pe pozitia j + 1 se constata ca nu sunt asezate in ordine,
deoarece v[j] > v[j+1], si se va produce, conform algoritmului, o interschimbare. Dupa
aceasta interschimbare, cel mai mare element, se afla pe pozitia j + 1. La pasul urmator se
compara elementul de pe pozitia j + 1 cu cel de pe pozitia j + 2 si, deoarece nu sunt aranjate
in ordine, se va produce o noua interschimbare. Dupa prima parcurgere exista certitudinea ca
cel mai mare element din vector se va afla pe ultima pozitie, pe pozitia n 1. Dupa o noua
parcurgere al doilea element ca marime din vector se va pozitiona pe penultima pozitie, acolo
unde-i este locul. Acest tip de pozitionare este, de fapt, motivul pentru care algoritmul este
numit sortarea cu bule, cele mai mari elemente ies la suprafata in ordinea descrescatoare a
marimii lor .
In cazul cel mai defavorabil, cand vectorul initial este ordonat descrescator, vor exista
n 1 parcurgeri ale vectorului, Tinand seama ca dupa fiecare parcurgere i, cel mai mare
element va fi pozitionat pe pozitia n i, la urmatoarea parcurgere ar fi inutila compararea
unui element cu elementele vectorului aflate pe pozitiile mai mari ca n 1 i, deoarece
acestea sunt cele mai mari din vector si asezate, deja, in ordine crescatoare.
Din acest motiv, se intalneste, deseori, urmatoarea implementare a algoritmului :

Descrierea algoritmului sortarii optimizate cu bule in pseudocod :
functie sortare_optima_bule_ (v, n)
inceput
pentru i = 0 la n 1 executa
pentru j = 0 la n 1 i executa
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1 -
i]
daca v[i]>v[i+1] atunci
inceput
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta se interschimba
elementele
aux = v[i]
v[i] = v[i+1]
v[i+1] = v[i]
sfarsit
sfarsit.

Descrierea algoritmului sortarii optimizate cu bule in C :
void sortare_optima1_bule (float v[], int n)
{
int i, j ; float aux ;
// buclele de parcurgere cu interschimbare
for (i = 0; i < n 1; i++)
for (j = 0; j < n 1 i ; j++)
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1
i]
if (v[j]>v[j+1])
{
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta
// se interschimba elementele intre ele
aux = v[j] ; v[j] = v[j+1] ; v[j+1] = aux ;
}
}
Cu aceasta implementare, mai eficienta, a algoritmului cu bule, programul complet de
ordonare este cel de mai jos :

Exemplul 3. Se considera orice vector v cu n elemente reale. Oricare ar fi vectorul furnizat,
sa se ordoneze crescator, utilizandu-se implementarea algoritmului sortarii optimizate cu
bule, de mai sus.

#include <iostream.h>
#include <conio.h>
# define nmax 20
int nr_comparari = 0; //contor nr comparari
int nr_treceri = 0; //contor nr treceri
void sortare_optima1_bule (float v[], int n)
{

int i, j ; float aux ;
// buclele de parcurgere cu interschimbare
for (i = 0; i < n - 1; i++)
{
nr_treceri++; //incrementare contor treceri
for (j = 0; j < n - 1 - i ; j++)
{
nr_comparari++; // incrementare contor comparari
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1
- i]
if (v[j]>v[j+1])
{
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta
// se interschimba elementele intre ele
aux = v[j] ; v[j] = v[j+1] ; v[j+1] = aux ;
}
}
}
}
void main ()
{
float v[100] ; int n,i ;char r='d' ;
while (r=='d')
{
// citirea dimensiunii vectorului
do
{
cout<<"\n dati numarul de componente ale vectorului [0,"<<nmax<<"]=" ;
cin>>n;
}
while ((n<0) || (n>nmax)) ;
// citirea componenteler vectorului
for (i=0 ; i<n ; i++)
{
cout<<"v["<<i<<"]=";
cin>>v[i];
}
// afisarea rezultatului testarii
cout<<"\n vectorul dat:" ;
for (i=0 ; i<n ; i++) cout<<v[i]<<' ' ;
// apelarea functiei de sortare cu bule
sortare_optima1_bule (v, n);
cout<<"\n vectorul ordonat:" ;
for (i=0 ; i<n ; i++) cout<<v[i]<<' ' ;
// afisarea numarului de comparari si treceri prin vector
cout<<"\n sortarea s-a facut cu "<<nr_comparari<<" comparari"
<<" si in "<<nr_treceri<<" treceri";
// initializarea numarului de comparari si treceri
nr_comparari = 0;
nr_treceri = 0;
cout<<"\n continuati ?(d/n):";
cin>>r;
}
}

Dandu-se cazul cel mai defavorabil, vectorul v = (5, 4, 3, 2, 1), ordonat descrescator,
pentru ordonarea sa crescatoare s-au efectuat 4 parcurgeri efectuandu-se 10 de comparari, iar
pentru cazul cel mai favorabil, vectorul v = (1, 2, 3, 4, 5), deja ordonat s-au efectuat tot 4
parcurgeri si 10 comparari.. In raport cu prima varianta a algoritmului se constata o
eficientizare la cel de-al doilea algoritm corespunzator cazului cel mai defavorabil.
Aceasta implementare a algotitmului de sortare cu bule, are o parte buna, deoarece
tine seama de faptul ca dupa o parcurgere i elementul cel mai mare va fi deplasat pe pozitia n
1 i, iar parcurgerea urmatoare, i + 1 se va face pana la pozitia n 1 i, exclusiv. Partea
necorespunzatoare a algoritmului consta in faptul ca vectorul va fi, in final, reparcurs, desi
acesta este deja sortat,
Pentru inlaturarea acestui neajuns, se va proceda la urmatorea implementare pentru
algoritmul de sortare cu bule :

Descrierea in pseudocod a algoritmului functiei de sortare cu bule cu un numar optim de
treceri
functie sortare_optima2_bule_ (v, n)
inceput
j = 0 ; // contor trecere
repeta
inceput
// se initializeaza variabila sortat cu adevarat, considerandu-se apriorii vectorul sortat
sortat = adevarat
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1]
pentru i=0 la n-2 j executa
inceput
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta se interschimba
elementele
// si variabila fanion sortat primeste valoarea fals
daca v[i]>v[i+1] atunci
inceput
aux = v[i]
v[i] = v[i+1]
v[i+1] = v[i]
sortat = fals
sfarsit
sfarsit
j =j+1 // incrementare contor trecere
cat timp (sortat = fals)
sfarsit.

Descrierea algoritmului sortarii cu bule in C, cu un numar optim de treceri :
void sortare_bule (float v[], int n)
{
bool sortat ; int i; float aux ;
int j = 0; // contor treceri
// bucla de testare cu interschimbare
do
{
// se initializeaza variabila sortat cu adevarat, considerandu-se apriorii vectorul sortat
bool sortat = true
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1]
for (i=0 ; i<n -1 j ; i++)
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta
// se interschimba elementele intre ele si variabila fanion sortat primeste valoarea
fals
if (v[i]>v[i+1])
{
aux = v[i] ; v[i] = v[i+1] ; v[i+1] = aux ;
sortat = false ;
}
j++ ; // incrementare contor treceri
}
while ( !sortat) ;
}
Un program complet se poate scrie, utilizand aceasta implementare, asemanator cu
exemplele anterioare.
Algoritmul este eficient in cazul in care avem un sir deja sortat in care au fost inserate cateva
elemente la stanga elementelor din vectorul initial sortat
In cazul sirului v = (1, 9, 6, 2, 3, 4, 5, 7) se evidentiaza urmatoarele treceri:
Prima trecere : v = (1, 6, 2, 3, 4, 5, 7, 9)
A doua trecere: v = (1, 2, 3, 4, 5, 6, 7, 9)
A treia trecere detecteaza ca sirul este sortat
Daca avem de sortat un sir in care s-au adaugat elemente la dreapta unui alt sir deja sortat
atunci algoritmul presupune mai multe treceri. Daca avem de sortat sirul v = (1, 3, 5, 6, 8, 9,
10, 0) atunci vom avea urmatoarele treceri :
Prima trecere : sirul v = (1, 3, 5, 6, 8, 9, 0, 10)
A doua trecere: sirul v = (1, 3, 5, 6, 8, 0, 9, 10)
A treia trecere: sirul v = (1, 3, 5, 6, 0, 8, 9, 10)
A patra trecere: sirul v = (1, 3, 5, 0, 6, 8, 9, 10)
A cincea trecere: sirul v = (1, 3, 0, 5, 6, 8, 9, 10)
A sasea trecere: sirul v = (1, 0, 3, 5, 6, 8, 9, 10)
A saptea trecere: sirul v = (0, 1, 3, 5, 6, 8, 9, 10)
A opta trecere gaseste sirul sortat v = (0, 1, 3, 5, 6, 8, 9, 10)
In exemplul de mai sus, desi am adaugat un singur element, pe 0, la dreapta unui alt
sir sortat algoritmul are nevoie de opt treceri. Se observa, daca am schimba sensul
parcurgerii, ca ar fi nevoie numai de o singura trecere pentru ordonare descrescatoare.
In concluzie, atunci cand stim ca avem de sortat un sir deja ordonat in care s-au
inserat la intamplare cateva elemente se pot alterna sensurile de parcurgere a sirului

Aoritmul de sortare cu bule a unui sir cu parcurgerea alternata a sirului
Descrierea in pseudocod a algoritmului :
functie sortare_alternanta_bule_ (v, n)
inceput
primul = 0 ; // precizarea primului element
ultimul = n - 1 ; // precizarea ultimului element
repeta
inceput
// parcurgerea sirului de la stanga la dreapta
// se initializeaza variabila sortat cu adevarat, considerandu-se apriorii vectorul sortat
sortat = adevarat
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1]
pentru i=0 la n-2 j executa
inceput
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta se interschimba
elementele
// si variabila fanion sortat primeste valoarea fals
daca v[i]>v[i+1] atunci
inceput
aux = v[i]
v[i] = v[i+1]
v[i+1] = v[i]
sortat = fals
sfarsit
sfarsit
ultimul = ultimul - 1 // decrementare pozitiei ultimului element
daca (sortat = fals)
inceput
// parcurgerea sirului de la dreapta la stanga
sortat = adevarat
pentru i = ultimul la primul pas 1 executa
inceput
daca v[i]<v[i+1] atunci
inceput
aux = v[i]
v[i] = v[i-1]
v[i-1] = v[i]
sortat = fals
sfarsit
sfarsit
primul = primul + 1 // incrementarea pozitiei primului element
sfarsit
cat timp (sortat = fals)
sfarsit.

Descrierea algoritmului in C :
void sortare_alternanta_bule (float v[], int n)
{
bool sortat ; int i; float aux ;
int primul = 0; // contorul pozitiei primului element
int ultimul = n-1; // contorul pozitiei ultimului element
// bucla de testare cu interschimbare
do
{
// parcurgerea sirului de la stanga la dreapta
// se initializeaza variabila sortat cu adevarat, considerandu-se apriorii vectorul sortat
bool sortat = true
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1]
for (i=primul ; i<ultimul; i++)
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta
// se interschimba elementele intre ele si variabila fanion sortat primeste valoarea
fals
if (v[i]>v[i+1])
{
aux = v[i] ; v[i] = v[i+1] ; v[i+1] = aux ;
sortat = false ;
}
ultimul -- ; // decrementare contor ultimei pozitii
// parcurgerea sirului de la dreapta la stanga
if ( !sortat)
{
sortat = true;
for (i=ultimul ; i>primul; i--)
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta
// se interschimba elementele intre ele si variabila fanion sortat primeste
valoarea fals
if (v[i]<v[i-1])
{
aux = v[i] ; v[i] = v[i-1] ; v[i-1] = aux ;
sortat = false ;
}
primul ++; // incrementare contorul primei pozitii
}
}
while ( !sortat) ;
}
Un program complet este descries mai jos, utilizand aceasta implementare,
asemanator cu exemplele anterioare.
Algoritmul este eficient in cazul in care avem un sir deja sortat in care au fost inserate cateva
elemente aleator in vectorul initial sortat.
Exemplul 4.
Se considera orice vector v cu n elemente reale. Oricare ar fi vectorul furnizat, sa se
ordoneze crescator, utilizandu-se sortarea alternanta cu bule cu un numar minim de treceri

#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
# define nmax 20
int nr_comparari = 0; //contor nr comparari
int nr_treceri = 0; //contor nr treceri
void sortare_alternanta_bule (float v[], int n)
{
bool sortat ; int i,k; float aux ;
int primul = 0; // contorul pozitiei primului element
int ultimul = n-1; // contorul pozitiei ultimului element
// bucla de testare cu interschimbare
do
{
// parcurgerea sirului de la stanga la dreapta
// se initializeaza variabila sortat cu adevarat, considerandu-se apriorii vectorul sortat
sortat = true;
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1]
for (i=primul ; i<ultimul; i++)
{
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta
// se interschimba elementele intre ele si variabila fanion sortat primeste valoarea fals
if (v[i]>v[i+1])
{
nr_comparari++;
aux = v[i] ; v[i] = v[i+1] ; v[i+1] = aux ;
sortat = false ;
}
}
ultimul-- ; // decrementare contor ultimei pozitii
nr_treceri++;
cout<<"\n vectorul dupa trecerea "<<nr_treceri<<':';
for (k = 0; k <= n - 1; k++) cout<<v[k]<<' ';
// parcurgerea sirului de la dreapta la stanga
if (!sortat)
{
sortat = true;
for (i=ultimul ; i>primul; i--)
{
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta
// se interschimba elementele intre ele si variabila fanion sortat primeste valoarea fals
if (v[i]<v[i-1])
{
nr_comparari++;
aux = v[i] ; v[i] = v[i-1] ; v[i-1] = aux ;
sortat = false ;
}
}
primul++; // incrementare contorul primei pozitii
nr_treceri++;
cout<<"\n vectorul dupa trecerea "<<nr_treceri<<':';
for (k = 0; k <= n - 1; k++) cout<<v[k]<<' ';
}
}
while (!sortat);
}
void main ()
{
float v[100] ; int n,i ;char r='d' ;
// redirectarea iesirii stdout intr-un fisier text, fisout
// in scopul listarii ulterioare a rezultatelor
// if((freopen("fisout","wt",stdout))==NULL)
// {
// printf("\n eroare de deschidere");
// exit(1);
// }
while (r=='d')
{
// citirea dimensiunii vectorului
do
{
cout<<"\n dati numarul de componente ale vectorului [0,"<<nmax<<"]=" ;
cin>>n;
}
while ((n<0) || (n>nmax)) ;
// citirea componenteler vectorului
for (i=0 ; i<n ; i++)
{
cout<<"v["<<i<<"]=";
cin>>v[i];
}
// afisarea rezultatului testarii
cout<<"\n vectorul dat:" ;
for (i=0 ; i<n ; i++) cout<<v[i]<<' ' ;
// apelarea functiei de sortare cu bule
sortare_alternanta_bule (v, n);
cout<<"\n vectorul ordonat:" ;
for (i=0 ; i<n ; i++) cout<<v[i]<<' ' ;
// afisarea numarului de comparari si treceri prin vector
cout<<"\n sortarea s-a facut cu "<<nr_comparari<<" comparari"
<<" si in "<<nr_treceri<<" treceri";
// initializarea numarului de comparari si treceri
nr_comparari = 0;
nr_treceri = 0;
cout<<"\n continuati ?(d/n):";
cin>>r;
}
}
Mai jos, sunt date cateva rezultate obtinute in urma executarii programului de mai sus :

Sortarea unui vector anterior sortat in care s-au inserat la stanga componentele 8 si 6
dati numarul de componente ale vectorului [0,20]=8
v[0]=1
v[1]=8
v[2]=6
v[3]=2
v[4]=3
v[5]=4
v[6]=5
v[7]=7
vectorul dat:1 8 6 2 3 4 5 7
vectorul dupa trecerea 1:1 6 2 3 4 5 7 8
vectorul dupa trecerea 2:1 2 6 3 4 5 7 8
vectorul dupa trecerea 3:1 2 3 4 5 6 7 8
vectorul dupa trecerea 4:1 2 3 4 5 6 7 8
vectorul ordonat:1 2 3 4 5 6 7 8
sortarea s-a facut cu 10 comparari si in 4 treceri

continuati ?(d/n):d
Sortarea unui vector anterior sortat in care s-a inserat la dreapta componenta 1
dati numarul de componente ale vectorului [0,20]=8
v[0]=2
v[1]=3
v[2]=4
v[3]=5
v[4]=6
v[5]=7
v[6]=1
v[7]=8
vectorul dat:2 3 4 5 6 7 1 8
vectorul dupa trecerea 1:2 3 4 5 6 1 7 8
vectorul dupa trecerea 2:1 2 3 4 5 6 7 8
vectorul dupa trecerea 3:1 2 3 4 5 6 7 8
vectorul ordonat:1 2 3 4 5 6 7 8
sortarea s-a facut cu 6 comparari si in 3 treceri

continuati ?(d/n):d
Sortarea unui vector anterior sortat in care s-au inserat aleator componentele 9 si 7
dati numarul de componente ale vectorului [0,20]=8
v[0]=1
v[1]=2
v[2]=3
v[3]=9
v[4]=7
v[5]=4
v[6]=5
v[7]=6
vectorul dat:1 2 3 9 7 4 5 6
vectorul dupa trecerea 1:1 2 3 7 4 5 6 9
vectorul dupa trecerea 2:1 2 3 4 7 5 6 9
vectorul dupa trecerea 3:1 2 3 4 5 6 7 9
vectorul dupa trecerea 4:1 2 3 4 5 6 7 9
vectorul ordonat:1 2 3 4 5 6 7 9
sortarea s-a facut cu 7 comparari si in 4 treceri
continuati ?(d/n):n

Algoritmul de sortare cu bule a unui sir cu parcurgerea alternata a sirului pana la
ultima interschimbare
Algoritmului anterior i se poate aduce o ultima imbunatatire, daca se tine cont de
pozitia (indexul) la care are loc ultima interschimbare. Daca la o parcurgere, de la stanga la
dreapta sau de la dreapta la stanga, ultima interschimbare are loc de pe pozitiile p si p+1,
respectiv p si p-1, atunci se poate spune ca elementele cu indexul mai mare ca p, respectiv
mai mic ca p, sunt deja ordonate.
Descrierea in pseudocod a algoritmului :
functie sortare_alternanta_bule_ (v, n)
inceput
primul = 0 ; // precizarea primului element
ultimul = n - 1 ; // precizarea ultimului element
repeta
inceput
// parcurgerea sirului de la stanga la dreapta
// se initializeaza variabila sortat cu adevarat, considerandu-se apriorii vectorul sortat
sortat = adevarat
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1]
pentru i=0 la n-2 j executa
inceput
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta se interschimba
elementele
// si variabila fanion sortat primeste valoarea fals
daca v[i]>v[i+1] atunci
inceput
aux = v[i]
v[i] = v[i+1]
v[i+1] = v[i]
sortat = fals
t = i; //retinerea indexului ultimei interschimbari
sfarsit
sfarsit
ultimul = t // ultima pozitie de comparat = ultimul index in care s-a produs o
intyerschimbare
daca (sortat = fals)
inceput
// parcurgerea sirului de la dreapta la stanga
sortat = adevarat
pentru i = ultimul la primul pas 1 executa
inceput
daca v[i]<v[i+1] atunci
inceput
aux = v[i]
v[i] = v[i-1]
v[i-1] = v[i]
sortat = fals
t = i; //retinerea indexului ultimei interschimbari
sfarsit
sfarsit
primul = t // prima pozitie de comparat = primul index in care s-a produs o
intyerschimbare
sfarsit
cat timp (sortat = fals)
sfarsit.

Descrierea algoritmului in C :
void sortare_alternanta_bule (float v[], int n)
{
bool sortat ; int i; float aux ;
int primul = 0; // contorul pozitiei primului element
int ultimul = n-1; // contorul pozitiei ultimului element
// bucla de testare cu interschimbare
do
{
// parcurgerea sirului de la stanga la dreapta
// se initializeaza variabila sortat cu adevarat, considerandu-se apriorii vectorul sortat
bool sortat = true
// se compara doua cate doua elementele vecine pentru orice i din intervalul [0, n-1]
for (i=primul ; i<ultimul; i++)
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta
// se interschimba elementele intre ele si variabila fanion sortat primeste valoarea
fals
if (v[i]>v[i+1])
{
aux = v[i] ; v[i] = v[i+1] ; v[i+1] = aux ;
sortat = false ;
t = i; //retinerea indexului ultimei interschimbari
}
ultimul = t // ultima pozitie de comparat = ultimul index in care s-a produs o
intyerschimbare
// parcurgerea sirului de la dreapta la stanga
if ( !sortat)
{
sortat = true;
for (i=ultimul ; i>primul; i--)
// daca cel putin doua elemente vecine nu sunt in ordinea ceruta
// se interschimba elementele intre ele si variabila fanion sortat primeste
valoarea fals
if (v[i]<v[i-1])
{
aux = v[i] ; v[i] = v[i-1] ; v[i-1] = aux ;
sortat = false ;
t = i; //retinerea indexului ultimei interschimbari
}
primul = t // prima pozitie de comparat = primul index in care s-a produs o
interschimbare
}
}
while ( !sortat) ;
}
Un program complet, ca si in exemplele anterioare, se poate scrie si testa cu usurinta.
2.2.2. Sortarea Rapida
Sortarea rapida foloseste algoritmul divide et impera si mai este cunoscuta sub numele
de sortarea prin interschimbare cu partitii. Acest algoritm presupune parcurgerea a trei etape :
1. Etapa Divide : vectorul V, format clin elementele cu indecii ntre s i d, notat n
continuare prin V[s..d], este partiionat n doi subvectori V[s..m] i V[m+1..d], fiecare parte
avnd cel puin un element, astfel nct fiecare element din prima parte este mai mic sau egal
dect oricare element din cea de-a doua parte.
2. Impera: cele dou pri sunt sortate apelnd recursiv pn cnd se ajunge la poriuni
formate dintr-un singur element.
3. Combin: avnd n vedere c fiecare subvector este sortat i cel mai mare element
clin subvectorul din stnga este mai mic sau egal dect cel mai mic element din subvectorul
din dreapta atunci ntregul vector este de fapt sortat.
Implementarea algoritmului:
void sortareRapida(int v[], int st, int dr)
{
int m = partitioneaza(v, st, dr);
if (st<m)
{
sortareRapida(v, st, m);
}
if ((m+ l)<dr)
{
sortareRapida(v, m + 1, dr);
}
}
"Munca" este fcut de fapt de procedura de partiionare. Exist mai multe moduri n care
putem mpri vectorul, dar urmtorul algoritm, inventat, de R. Sedgevvick, pare a fi cel mai
bun: se pornete de la ambele capete, folosind doi indicatori, i pentru partea stng, j pentru
partea din dreapta, cutndu-se elementele care ar trebui s fie n cealalt parte; n momentul
n care se gsesc elementele se verific dac i < j; dac da se interschimb cele dou elemente
i se continu algoritmul, altfel algoritmul ntoarce valoarea lui j; element de referin se
consider ca fiind primul element din vector.

Descrierea algoritmului:
Urmtorul algoritm partiioneaz vectorul v[st..dr] n doi subvectori v[st..m] i
v[m+l..dr] astfel nct toate elementele din primul subvector s fie mai mici sau egale dect
oricare element din cel de-al doilea subvector, la final ntorcnd valoarea lui m.
P1. Se iniializeaz elementul de referin x cu v[st], i cu st i j cu dr.
P2. Dac v[i] >= x se trece la pasul P5. Altfel se continu cu pasul urmtor.
P3. Se incrementeaz i.
P4. Se continu cu pasul P2.
P5. Dac v[j] <= x se trece la pasul P8. Altfel se continu cu pasul urmtor.
P6. Se decrementeaz valoarea lui j.
P7. Se continu cu pasul P5.
P8. Dac i >= j algoritmul se ncheie ntorcnd valoarea lui j. Altfel se continu cu pasul P9.
P9. Se interschimb v[i] cu v[j].
P10. Se incrementeaz i.
P11. Se decrementeaz j.
PI2. Se continu cu pasul P2,

Descrierea algoritmului in C:
int partitioneaza(int v[], int st, int dr)
{
int i = st; int j = dr; int x = v[st];
do
{
while (x > v[i])
{
i++;
}
while (x < v[j])
{
j--;
}
if('<j)
{
interschimba(v[i], vfj]);
i++;
j--;
}
else
{
return j;
}
} while (true);
}
Dac v[i] este mai mic dect elementul de referin atunci cu certitudine el face parte din
primul subvector, altfel, este un element care poate fi plasat n cel de-al doilea subvector.
Primul ciclu caut elemente mai mari sau egale cu elementul de referin.
Dac v[j] este mai mare dect elementul de referin atunci cu certitudine el face parte din cel
de-al doilea subvector, altfel, este un element care poate fi plasat n primul subvector. Cel de-
al doilea ciclu caut elemente mai mici sau egale cu elementul de referin.
Primul lucru pe care trebuie s-1 demonstrm este c cele dou cicluri se termin. Prima
valoare a lui i pentru care se termin primul ciclu este chiar st deoarece acesta este elementul
de referin. Avem mai multe cazuri:
Cazul 1: x este cel mai mic element din vector, ne mai existnd nici un element egal cu el.
In cazul n care x este cel mai mic element din vector, neexistnd nici un element egal cu.el,
cel de-al doilea ciclu se termin tot cu j egal cu st. In acest caz partiionarea se ncheie, cel
mai din dreapta element al subvectorului stng fiind cel de pe poziia j.
Cazul II: Exist cel puin un element mai mic sau egal cu x.
In acest caz, cel de-al doilea ciclu se termin pe primul element mai mic sau egal dect x.
Deoarece acest element se afl n dreapta primului element are loc interschimbarea celor
dou elemente. S presupunem acum c ultima interschimbare pe care o efectueaz
algoritmul este cea dintre elementele v[p] i v[q], cu p <q. Dup interschimbare avem v[p] <=
x i x <= v[q]. Acum avem dou subcazuri:
a) q - p = 1. In acest caz cele dou elemente au fost i au rmas vecine. Cele dou
cicluri se ncheie cu i = q i j = p. Este evident c algoritmul se ncheie ntorcnd indexul
celui mai din dreapta element ai subvectorului stng, adic valoarea lui j.
b) q - p > 1. Este evident c cele dou cicluri se ncheie, n cel mai ru caz cnd
primul ciclu l va gsi pe v[q], iar cel de-al doilea ciclu l va gsi pe v[p]. Deoarece nu se mai
efectueaz nici o interschimbare, cele dou cicluri se ncheie cu i >= j. Avem v[k] < x, pentru
oricare k din intervalul
[p + 1, i - 1] i x < v[m] pentru oricare m din intervalul [j+1, q-1]. Este evident c cele dou
intervale, [p + 1, i - 1] i [j+1, q-1], sunt disjuncte. Avem deci i - 1 < j + 1, de unde rezult c
i - j < 2.
O s ilustrm funcionarea algoritmului cu urmtorul exemplu:
Partiionarea 1: Prin partiionarea irului: 7 13 100 1 54 87 5 13 44 99 89 2 9 6 35 88 se obin
urmtoarele partiii: 6 2 5 1 i : 54 87 100 13 44 99 89 13 9 7 35 88
Partiionarea 2. Prin partiionarea irului: 6 2 5 1 se obin partiiile: 1 2 5 si 6
Partiionarea 3: Prin partiionarea irului: 1 2 5 se obin partiiile: 1 i 2 5
Partiionarea 4. Prin partiionarea irului 2 5 se obin partiiile: 2 i 5
Partiionarea 5. Prin partiionarea irului: 54 87 100 13 44 99 89 13 9 7 35 88 se obin
partiiile:
35 7 9 13 44 13 i 89 99 100 87 54 88
Partiionarea 6. Prin partiionarea irului: 35 7 9 13 44 13 se obin partiiile:13 7 9 13 i 44
35
Partitionarea 7. Prin partitionarea irului: 13 7 9 13 se obin partiiile: 13 7 9 i 13
Partitionarea 8. Prin partitionarea irului: 13 7 9 se obin partiiile: 9 7 i 13
Partitionarea 9. Prin partitionarea irului: 9 7 se obin partiiile: 7 i 9
Partitionarea 10. Prin partitionarea irului: 44 35 se obin partiiile: 35 i 44
Partitionarea 11. Prin partitionarea irului: 89 99 100 87 54 88 se obin partiiile: 88 54 87 i
100 99 89
Partiionarea 12. Prin partiionarea irului: 88 54 87 se obin partiiile: 87 54 i 88
Partiionarea 13. Prin partiionarea irului: 87 54 se obin partiiile: 54 i 87
Partiionarea 14. Prin partiionarea irului: 100 99 89 se obin partiiile: 89 99 i 100
Partiionarea 15. Prin partiionarea irului: 89 99 se obin partiiile:89 i 99
n final se obine irul ordonat crescator: 1 2 5 6 7 9 13 13 35 44 54 87 88 89 99 100
In cel mai ru caz, partiionarea produce o regiune cu un singur element. Cel mai bun
caz se obine atunci cnd vectorul este mprit n dou pri egale. Timpul mediu este mai
apropiat de cel mai bun caz, adncimea arborelui de partiionare fiind aproximativ egal cu
log
2
n, iar pentru fiecare nivel sunt comparate toate elementele arborelui cu elementele de
referin, ceea ce nseamn c avem o complexitate de ordinul n. Deci complexitatea
algoritmului este de ordinul n*log
2
n, notat cu
O(n*log
2
n). n cel mai ru caz, care se obine de exemplu atunci cnd irul este deja sortat,
adncimea arborelui este n, ceea ce ne duce la complexitatea 0(n
2
). Pentru a evita obinerea
celui mai ru caz se poate modifica procedura de partiionare astfel nct elementul de
referin s fie ales aleator.

int part.itionareAleatoare(int v[], int st, int dr)
{
int i = st + rand() % (dr - st + 1);
interschimba(v[st], v[i]);
return partitioneaza(v, st, dr);
}
Plasm elementul de referin pe .prima poziie deoarece este nevoie s avem
certitudinea c elementul de referin se gsete i n alt parte dect pe ultima poziie. Dac
elementul de referin ar fi cel mai mare element din vector i ar fi amplasat pe ultima poziie,
atunci algoritmul s-ar ncheia cu i = j = dr. n acest caz vectorul v[j + 1..dr] ar avea 0
elemente.

2.2.3. Sortarea prin Selecie Direct,
Este clar c pe prima poziie ntr-un ir ordonat cresctor va fi amplasat cel mai mic element
al irului, pe cea de-a doua poziie va fi aezat urmtorul element ca mrime i aa mai
departe.
Descrierea algoritmului:
Dndu-se vectorul v cu n elemente, urmtorul algoritm rearanjeaz elementele vectorului
astfel nct la final acestea s fie n ordine, v[0] < v[ 1 ] < ... < v[n - 2] < v[n - 1 ].
P1. Se iniializeaz i cu 0.
P2. Dac i este egal cu n - 1 algoritmul se ncheie, altfel se continu cu pasul P3.
P3. Se iniializeaz index Minim cu i i j cu i + 1.
P4. Dac j este egal cu n se continu cu pasul P8, altfel se continu cu pasul P5.
P5. Dac v[j] < v[indexMinim] atunci indexMinim ia valoarea lui j.
P6. Se incrementeaz valoarea lui j.
P7. Se continu cu pasul P4.
P8. Dac i este diferit de indexMinim se interschimb v[i] cu v[indexMiniml.
P9. .Se incrementeaz valoarea lui i.
P10. Se continu cu pasul P2.

Descrierea algoritmului in C:
void sortareSeiectie(int v[], int n)
{
int i; intj;
int indexMinim;
for (i = 0; i < n - 1; i++)
{
indexMinim = i;
for (j = i + 1; j < n; j++)
{
if v[j] < v[indexMinim])
{
indexMinim = j; )
}
}
if (indexMinim != i)
{
interschimba(v[i], vfindexMinim]);
}
}
}
Uneori este preferat urmtoarea variant:

void sortareSelectie2(int v[], int n)
{
int i; int j;
for (i = 0; i < n - 1; i++)
{
for(j = i + l;j<n;j++)
{
if(v[j]<v[i])
{
interschimba(v[i], v[j]);
}
}
}
}
Aceast variant este mai compact, dar mult mai lent, nlocuinclu-se o singur
instruciune de atribuire cu trei instruciuni similare.
Algoritmul, n prima sa variant, efectueaz pentru fiecare i, n-i-1 comparaii i cel
mult o interschimbare. Deci avem (n - 1) + (n - 2) + ... + 2 + 1 = n * ( n - 1) / 2 comparaii
i maxim n- 1 interschimbri. Avantajul acestui algoritm, comparativ cu sortarea cu bule,
const n faptul c efectueaz puine deplasri de date.
2.2.4. Sortarea Heap
Aceast sortare este o mbuntire a seleciei directe. Este evident c un algoritm de selectare
a maximului dintr-un vector de n elemente trebuie s efectueze cel puin n - 1 comparaii. Dar
acest lucru este valabil doar pentru prima etap, n urmtoarele etape ne putem folosi de
informaiile acumulate n etapele anterioare. Imaginai-v o structur ierarhic care are n vrf
un singur element. Acest element are dou "ajutoare" care au rangul mai mic dect al su,
acestea au la rndul lor cte dou ajutoare de rang mai mic i aa mai departe. Fiecare
element din aceast structur, are doi subordonai, iar aceti subordonai au un rang mai mic
dect superiorul lor direct. Excepie fac elementele de pe ultimul nivel, care nu au nici un
subordonat, i elementele de pe penultimul nivel, care pot s aib doar un singur subordonat.
De exemplu, fie urmtoarea structur:
100
99 87
88 89 9 35
13 44 54 13 2 7 6 5

Este evident c cel mai mare element este cel din vrful ierarhiei. Dac scoatem acest
element, pentru a-l nlocui trebuie s comparm subordonaii direci, avansnd cel mai mare
n grad dintre acetia. Proasptul avansat va fi nlocuit de cel mai mare n grad dintre
subordonaii si direci i aa mai departe.
99
89 87
88 54 9 35
13 44 x 13 2 7 6 5
Prin x am simbolizat lipsa unui subordonat ai unui eiement care nu este frunz n arbore,
pentru ca structura s rmn clar. La urmtorul pas avem:
89
88 87
44 54 9 35
13 x x 13 2 7 6 5
Este evident c o astfel de structur ne ajut la selectarea rapid a celui mai mare element.
Prima problem const n construirea ct mai rapid a unei astfel de structuri, pornind de Ia
un vector oarecare.
Dndu-se un vector v cu n elemente avnd indecii de la 1 la n, spunem c acesta formeaz o
structur HEAP dac v[i / 2] v[i] pentru orice i ntreg din intervalul [2, n]
Aceast structur este de fapt similar celei descrise, anterior, avnd:
v[l] v[2], v[l] v[3], v[2] v[4], v[2] v[5], v[3] v[6], v[3] v[7], ...
In general, avem:
v[i] v[2*i ] i v[i] v[2*i + 1] cu condiia ca att i, (2*i) i (2*i + 1) s fie n intervalul [1,
n].
Este evident c cel mai mare element se afl amplasat pe prima poziie n vector.

Descrierea algoritmului:
Dndu-se vectorul v cu n elemente, urmtorul algoritm rearanjeaz elementele
vectorului astfel nct Sa final acestea s fie n ordine, v[l] v[2] ... v[n - 1] v[n].
P1. Se dau valorile st = n / 2 + 1 i dr = n.
P2. Dac st > 1 atunci avem st = st - 1 i cheie = v[st],
altfel efectum cheie = v[dr], v[dr] = v[1] i dr = dr - 1.
Dac dr devine 1 se face atribuirea v[l] = cheie i algoritmul se ncheie.
P3. Se atribuie j = st.
P4. Se atribuie i = j, j = 2 * j.
Dac j < dr se trece ia pasul P5.
Dac j = dr se trece la pasul P6.
Dac j > dr se trece la pasul P8.
P5. Dac v[j] < v[j + 1] se face atribuirea j = j + 1.
P6. Dac cheie >= v[j] se trece la pasul P8.
P7. Se efectueaz atribuirea v[i] = v[j] i se reia pasul P4.
P8. Se efectueaz atribuirea v[i] = cheie i se reia pasul P2.

Pentru claritate, o s "spargem" algoritmul n mai multe buci. Mai nti o s scriem
o procedur care primete un vector cu proprietatea c elementele din intervalul [index+1,n-
1] formeaz un HEAP i are ca efect transformarea n HEAP a elementelor cuprinse n
intervalul [index, n-1].

Descrierea algoritmului in C:
void heapify(int v[], int index, int n)
{
int left = index * 2 + 1; int right = left + 1;
if (left >= n)
{
return;
}
int largest - index;
if(v[left]> v[index])
{
largest = left;
}
if(right < n && v[right] > v[largest])
{
largest - right;
}
if (index != largest)
{
interschimba(v[index], vflargest]);
heapify(v, iargest, n);
}
}
Deoarece n C/C++ primul element dintr-un vector are indexul 0, spunem c acesta
formeaz un HEAP dac pentru orice i avem v[i] v[2*i + 1] i v[i] v[2
:i:
i -l- 2], cu
condiia ca toi indecii s fie n intervalul [0, n - 1].
Fiindc elementele din dreapta lui index formeaz un HEAP trebuie s comparm elementul
de pe aceast poziie cu elementele de pe poziiile (2*index. + 1) i (2*index + 2), cu condiia
ca cel puin unul dintre acestea s fie n vector. Dac nici una dintre aceste poziii nu face
parte din vector sau dac elementul de pe poziia index este mai mare sau egal cu celelalte
dou elemente, procedura se ncheie. Altfel se interschimb elementul de pe poziia index cu
elementul cel mai mare dintre celelalte dou. In urma acestei interschirnbri nu mai avem
certitudinea c elementele din intervalul [largest, n - 1] mai formeaz un HEAP, unde largest
este poziia pe care s-a aflat cel mai mare element nainte de interschimbare. Dar elementele
din intervalul [largest + 1, n - 1] formeaz un HEAP, deoarece nu am operat nicio modificare
n acest interval. De aceea, trebuie s aplicm aceeai procedur pentru elementul aflat pe
poziia largest.
In continuare o s folosim aceast procedur pentru a transforma vectorul ntr-un
HEAP:

void construieteHeap(int v[], int n)
{
for (int i = (n-1)/2; i >= 0; i--)
{
heapify(v, i, n);
}
}
Incepem cu elementul aflat la jumtatea vectorului deoarece elementele din dreapta
lui nu mai pot avea "subordonai". Dup ce am transformat vectorul ntr-un HEAP, sortarea
este foarte simpl: primul element, care este maximul, este interschimbat cu elementul de pe
ultima poziie. Dup aceast operaie maximul l-am amplasat pe poziia corect, dar vectorul
"rmas", v[0..n-2] nu mai formeaz un HEAP, datorit elementului aflat pe prima poziie. De
aceea trebuie s apelm heapify pentru a-1 transforma din nou n HEAP:

void sortareHeap(int v[], int n)
{
construiesteHeap(v, n);
for(int i = n - 1; i > 0; i--)
{
interschimba(v[0], v[i]);
heapify(v, 0, i);
}
}
Pentru a exemplifica funcionarea algoritmului o s ncepem cu construirea unui HEAP,
plecand de la irul: 7 13 100 1 54 87 5 13 44 99 89 2 9 6 35 88
Dup pasul 1, poriunea [7..15] formeaz un heap: 7 13 100 1 54 87 5 [88 44 99 89 2 9 6 35
13
Dup pasul 2, poriunea [6..15] formeaz un heap: 7 13 100 1 54 87 [35 88 44 99 89 2 9 6 5
13
Dup pasul 3, poriunea [5..15] formeaz un heap: 7 13 100 1 54 [87 35 88 44 99 89 2 9 6 5
13
Dup pasul 4, poriunea [4..15] formeaz un heap: 7 13 100 1 [99 87 35 88 44 54 89 2 9 6 5
13
Dup pasul 5, poriunea [3.. 15] formeaz un heap:7 13 100 [88 99 87 35 13 44 54 89 2 9 6 5
1
Dup pasul 6, poriunea [2.. 15] formeaz un heap:7 13 [100 88 99 87 35 13 44 54 89 2 9 6 5
1
Dup pasul 7, poriunea [1..15] formeaz un heap:7 [99 100 88 89 87 35 13 44 54 13 2 9 6 5
1
Dup pasul 8, poriunea [0..15J formeaz un heap: [100 99 87 88 89 9 35 13 44 54 13 2 7 6 5
1
In continuare se extrag maximele pe rnd:
Dup pasul 9, poriunea [15..15] este sortata iar partea din stnga formeaz un heap:
99 89 87 88 54 9 35 13 44 1 13 2 7 6 5 100
Dup pasul 10, poriunea [14..15] este sortata iar partea din stnga formeaz un heap:
89 88 87 44 54 9 35 13 5 1 13 2 7 6 99 100
Dup pasul 11, poriunea [13..15] este sortata iar partea din stnga formeaz un heap:
88 54 87 44 13 9 35 13 5 16 2 7 89 99 100
Dup pasul 12, poriunea [12..15] este sortata iar partea din stnga formeaz un heap:
87 54 35 44 13 9 7 13 5 16 2 88 89 99 100
Dup pasul 13, poriunea [11..15] este sortata iar partea din stnga formeaz un heap:
54 44 35 13 13 9 7 2 5 1 6 87 88 89 99 100
Dup pasul 14, poriunea [10..15] este sortata iar partea din stnga formeaz un heap:
44 13 35 6 13 9 7 2 5 1 54 87 88 89 99 100
Dup pasul 15, poriunea [9..15] este sortata iar partea din stnga formeaz unheap:
35 13 9 6 13 17 2 5 44 54 87 88 89 99 !00
Dup pasul 16, poriunea [8..15] este sortata iar partea din stnga formeaz un heap:
13 13 9 6 5 17 2 35 44 54 87 88 89 99 100
Dup pasul 17, poriunea [7..15] este sortata iar partea din stnga formeaz un heap:
13 6 9 2 5 1 7 13 35 44 54 87 88 89 99 100
Dup pasul 18, poriunea [6,.15] este sortata iar partea din stnga formeaz un heap:
9 6 7 2 5 1 13 13 35 44 54 87 88 89 99 100
Dup pasul 19, poriunea [5..15] este sortata iar partea din stnga formeaz un heap:
7 6 1 2 5 9 13 13 35 44 54 87 88 89 99 100
Dup pasul 20, poriunea [4..15] este sortata iar partea din stnga formeaz un heap:
6 5 1 2 7 9 13 13 35 44 54 87 88 89 99 100
Dup pasul 21, poriunea [3..15] este sortata iar partea din stnga formeaz un heap:
5 2 16 7 9 13 13 35 44 54 87 88 89 99 100
Dup pasul 22, poriunea [2..15] este sortata iar partea din stnga formeaz un heap:
2 15 6 7 9 13 13 35 44 54 87 88 89 99 100
Dup pasul 23, poriunea [1..15] este sortata iar partea din stnga formeaz un heap:
12 5 6 7 9 13 13 35 44 54. 87 88 89 99 100
Acest algoritm are o complexitate garantat de O(n*log
2
n).

Sortarea prin inserie Direct,
Acest algoritm este folosit de juctorii de cri care-i aranjeaz crile pe msur ce le
primesc, insernclu-le acolo unde este locul.
Descrierea algoritmului:
Dndu-se vectorul v cu n elemente, urmtorul algoritm rearanjeaz elementele vectorului
astfel
nct la final acestea s fie n ordine, v[0] . v[l] .... . v[n - 2] .v[n - 1]
PI. Se d lui i valoarea 1.
P2. Dac i este egal cu n algoritmul se ncheie, altfel algoritmul continu cu pasul P3.
P3. Se d lui j valoarea 0.
P4. Dac v[i] < v[j] se trece la pasul P7, altfel se continu cu pasul P5.
P5. Se incrementeaz valoarea lui j.
P6. Se continu cu pasul P4.
P7. Dac i = j se sare la pasul P14, altfel se continu cu pasul P8.
P8. Se fac atribuirile k = i - 1 i temp = v[i|.
P9. Dac k < j se continu cu pasul P13, altfel se continu cu pasul P10.
PIO. Se efectueaz atribuirea v[k + 1] = v[k].
PI 1. Se decrementeaz valoarea lui k.
PI 2. Se continu cu pasul P9.
PI 3. Se efectueaz atribuirea v[j] = temp.
PI4. Se incrementeaz i.
PI5. Se continu cu pasul P2.

Descrierea algoritmului in C:
void sortare!nsertie(int v[], int n)
{
int i; int j; int k; int temp;
for (i = 1; i < n; i++)
{
j = 0;
while(v['j]<v[i])
{
j++;
}
if(j<i)
{
temp = v[i];
for (k = i - 1; k>=j; k--)
{
v[k+ 1] = v[k];
}
v[j] = ternp;
}
}
}
Poriunea de cod:
j=0;
while (v[j] < v[i])
{
j++;
}
determin poziia n care trebuie inserat elementul v[i] n irul ordonat v[0..i 1]. Dup ce se
determin aceast poziie, dac trebuie deplasat elementul de pe poziia i, se pune elementul
v[i] deoparte:
temp = v[i];
Acum trebuie s i se fac loc lui v[i] pentru a-1 insera pe poziia j. Pentru aceasta se
deplaseaz toate elementele din intervalul [j, i - 1], ncepnd cu cel mai din dreapta element:
for(k = i- 1; k>=j; k-)
{
v[k+l] = v[k];
}
Dup care se insereaz elementul pe care l-am pus deoparte:
v[j] = temp;
Algoritmul se repet pentru toate elementele din intervalul [1, n - 1]. Cel mai defavorabil
timp se obine n cazul n care vectorul este sortat descresctor, n acest caz avnd cele mai
multe deplasri . Cel mai bun timp este obinut dac vectorul este deja sortat.

2.2.5. Sortarea Shell
Cea mai costisitoare operaie n cazul sortrii prin inserie direct o constituie
deplasarea elementelor la dreapta pentru a face loc elementului care trebuie inserat. De aceea
avem nevoie de un mecanism prin care nregistrrile s fac salturi mari. Acest mecanism a
fost inventat de Donald Shell i const n mprirea irului iniial n p
i
subiruri i sortarea
acestora pe rnd folosind sortarea prin inserie direct, elementele vecine ale unui subir
aflndu-se a distana p
i
n irul iniial. Procedeul se repet pentru o valoare a pasului din ce
n ce mai mic, ncheindu-se pentru un pas egal cu 1.

Descrierea algoritmului.
Dndu-se vectorul v cu n elemente, urmtorul algoritm rearanjeaz elementele
vectorului astfel nct la final acestea s fie n ordine, v[0] v[l] ... v[n - 2] v[n - 1],
folosind vectorul pas cu nrPai elemente, pas[0] fiind egal cu 1.
P1. Se d lui p valoarea nrPasi - 1.
P2. Dac p este egal cu - 1 algoritmul se ncheie, altfel se continu cu pasul P3.
P3. Se d lui start vaioarea 0.
P4. Dac start este egal cu pas[p] se continu cu pasul P22, altfel se continu cu pasul P5.
P5. Se d lui i valoarea start + pas[p].
P6. Dac i este mai mare sau egal cu n se continu cu pasul P20, altfel algoritmul continu cu
pasul P7. P7. Se d lui j valoarea start.
P8. Dac v[i] <= v[j] se trece la pasul P11, altfel se continu cu pasul P9.
P9. Se incrementeaz valoarea lui j.
P10. Se continu cu pasul P8.
P1l. Dac i este egal cu j se sare la pasul P18, altfel se continu cu pasul P12.
P12. Se fac atribuirile k = i - 1 i ternp = v[i].
P13. Dac k < j se continu cu pasul P17, altfel se continu cu pasul P14.
P14. Se efectueaz atribuirea v[k + 1] = v[k].
PI5. Se decrementeaz valoarea lui k.
P16. Se continu cu pasul P13.
P17. Se efectueaz atribuirea v[j] = temp.
P18. Se incrementeaz i.
P19. Se continu cu pasul P6
P20. Se incrementeaz valoarea lui start.
P21. Se continu cu pasul P4.
P22. Se decrementeaz valoarea lui p.
P23. Se continu cu pasul P2.

Descrierea algoritmului in C :
void sorteazaSubsir(int v[], int start, int pas, int n)
{
int i; int j; int k; int temp;
for (i = start + pas; i < n; i += pas)
{
j = start;
while(v[j] < v[i])
{
j += pas;
}
if(j<i)
{
temp = v[i];
for (k = i-pas; k >= j; k =k-pas)
{
v[k + pas] = v[k];
}
v[j] = temp;
}
}
}

void sortareShell(int v[], int n, int pas[], int nrPasi)
{
int i;
int j;
for (i=nrPasi-1; i >= 0; i--)
{
for(j = 0;j<pas[i];j++)
{
sorteazaSubsir(v, j, pas[i], n);
}
}
}
Pentru exemplificare ne propunem s sortm irul:
16 15 14 13 12 II 10 9 8 7 6 5 4 3 2 1 cu paii: 1, 3, 5, 7
Dup sortarea cu pasul 7 s-au efectuat 11 deplasri:
2 1 7 6 5 4 3 9 8 14 13 12 11 10 16 15
Dup sortarea cu pasul 5 s-au efectuat 11 deplasri:
2 17 6 5 4 3 9 8 14 13 12 11 10 16 15
Dup sortarea cu pasul 3 s-au efectuat 15 deplasri:
2 1 4 3 5 7 6 9 8 11 10 12 14 13 16 15
Dup sortarea cu pasul 1 s-au efectuat 22 deplasri:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Se observ c sortarea cu. pasul 5 nu are nici un efect. Timpul de rulare depinde att de
numrul de pai ct i de valorile pe care le au aceti pai. A. A. Papernov i G. V. Stasevici
au demonstrat urmtoarea teorem:
Timpul de rulare al sortrii Shell este 0(n
3/2
) atunci cnd paii sunt generai cu urmtoarea
formula: h
s
= 2
x+1
+ 1, cu 0 < s < t= log
2
n.

2.2.6. Sortarea prin Fuziune.
Sortarea prin fuziune (MergeSort), ca i sortarea rapid, folosete divide el impera:
1. Divide: vectorul V, format din elementele cu indecii ntre s i d, notat n continuare prin
V[s..d], este mprit pe jumtate n doi subvectori V[s..m] i V[m+I..d],
2. Impera: cele dou pri sunt sortate apelnd recursiv pn cnd se ajunge la poriuni
formate dintr-un singur element.
3. Combin: se combin cele dou jumti innd cont de faptul c fiecare snbvector este
sortat. Spre deosebire de sortarea rapid, unde greul cade pe etapa de mprire, aici partea
mai complicat este fcut n etapa de combinare a rezultatelor. Implementarea algoritmului
este prezentat n continuare:

void sortareFuziuneOnt v[], ini s, int d)
{
int m = (s + d) / 2;
if (s < m)
{
sortareFuziune(v, s, m);
}
if(m+l<d)
{
sortareFuziune(v, m + 1, d);
}
coinbina(v, s, m, d);
}





Descrierea algoritmului :
Urmtorul algoritm primete vectorul v[st..dr] cu elementele din subvectorii v[st...m],
v[m+l..dr] ordonate cresctor i are ca efect combinarea celor doi subvectori astfel nct
ntreg vectorul, de la st la dr, s fie ordonat cresctor, folosind un vector temporar.

P1. Se efectueaz urmtoarele iniializri: i = st, j = m + 1 i k = 0.
P2. Dac i > m sau j > dr se continu, cu pasul P11, altfel se continu cu pasul P3.
P3. Dac v[i] > v[j] se continu cu pasul P7, altfel se continu cu pasul P4.
P4. Se efectueaz atribuirea temp[k] = v[i].
P5. Se incrementeaz i.
P6. Se continu cu pasul P9.
P7. Se efectueaz atribuirea temp[k] = v[j].
P8. Se incrementeaz j.
P9. Se incrementeaz k.
P10. Se continu cu pasul P2.
P11. Dac i > m se continu cu pasul P16, altfel se continu cu pasul P12.
P12. Se efectueaz atribuirea temp[k] = v[i].
P13. Se incrementeaz i.
P14. Se incrementeaz k.
P15. Se continu cu P11.
P16. Dac j > dr se continu cu pasul P21, altfel se continu cu pasul P17.
P17. Se efectueaz atribuirea temp[k] = v[j].
PI8. Se incrementeazj.
P19. Se incrementeaz k.
P20. Se continu cu P16.
P21. Se copiaz coninutul vectorului temp n v, ncepnd cu adresa lui v[st] i algoritmul se
ncheie.

Descrierea algoritmului in C :
Varianta C++ aloc memorie pentru vectorul temporar la nceputul funciei, memorie care va
fi eliberat la final. Copierea vectorului se face cu ajutorul funciei niemcpy, care este
varianta cea mai bun pentru copierea zonelor de memorie disjuncte:
void combina(int v[], int s, int m, int d)
{
int i = s; int. j = m + 1;
int *temp = new injd - s + 1]; int k = 0;
while ((i <= ni) && (j <= d))
{
if(v[i] < v[j])
{
temp[k] = v[i];
}
else
{
temp[k] = v[j];
j++;
}
k++;
}
for ( ; i <= m; i++)
{
temp[k] = v[i]; k++;
}
for ( ; j <= d; j++)
{
temp[k] = v[j];
k++;
}
memcpy(&v[s], temp, (d - s + 1) * sizeof(int));
delete temp;
}
Algoritmul este simplu: se ncepe cu capetele din stnga ale subvectorilor, i i j fiind
indicatori ctre ceie mai mici elemente din subvectori care nu au fost nc mutate n vectorul
temporar. Ct timp ambii subvectori mai au elemente care nu au fost nc mutate se va muta
n vectorul temporar cel mai mic dintre v[i] i v[j], dup care se incrementeaz indexul
corespunztor. Indexul k arat prima poziie liber din vectorul temporar i firete c va fi
incrementat dup fiecare mutare. Dup ce se termin unul din subvectori se vor muta toate
elementele rmase din cellalt subvector.
Adncimea arborelui'de partiionare este de log
2
n, indiferent de dispunerea
elementelor vectorului. La fiecare nivel avem n atribuiri i n cel mai defavorabil caz 3n
comparaii, iar n cel mai favorabil caz 2n comparaii. Numrul mare de comparaii se
datoreaz faptului c pentru a selecta elementul care trebuie mutat n vectorul temporar,
atunci cnd ambii vectori mai au elemente care nu au fost mutate, se fac trei comparaii: dou
comparaii pentru a se verifica dac ambii subvectori mai au elemente i o comparaie pentru
a vedea care element este mai mic.
O implementare, utilizat foarte des, pleac de la ideea c elementele se iau pe rnd:
ct timp primul subvector mai are elemente i elementul de la captul primului subvector este
mai mic dect elementul de la captul celui de-al doilea subvector se "arde" captul primului
subvector dup care se efectueaz operaia simetric. Aceast etap se ncheie atunci cnd se
termin unul dintre subvectori:
void combina2(int vf], int s, ini m, int d)
{
int i = s;
int j = m + 1;
int *temp = new int[d - s + 1];
int k = 0;
while ((i <= m) && (j <= d))
{
while ((i <= m) && (v[i] < v[j]))
{
temp[k] = v[i]; i++; k++;
}
while((j <= d) && (v[i] >= v[j]))
{
temp[k] = v[j];
k++;
}
}
for( ; i <= m; i++)
{
temp[k] = v[i];
k++;
}
for ( ; j <= d; j++)
{
temp[k] = v[j];
k++;
}
memcpy(&v[s], ternp, (d - s + 1) * sizeof(int));
delete temp;
}

Acum n cel mai favorabil caz, cnd unul din subvectori are toate elementele mai mici
dect oricare dintre elementele celui de-al doilea subvector, se efectueaz 3/2n comparaii.
Dar n cel mai defavorabil caz, cnd se iau elemente pe rnd din fiecare subvector, avem 3n
comparaii, pentru fiecare 2 elemente mutate efectundu-se 6 comparaii: de cte 2, ori (i <=
m) i (j <= d), apoi (v[i] < v[j]) i (v[i] >= v[j]). Primele comparaii le putem reduce uor:
atunci cnd oricare dintre cicluri interioare trebuie s se termine fiindc s-a terminat unul
dintre subvectori, atunci este evident c trebuie s se termine i ciclul exterior. Acest lucru se
poate face printr-un salt n afara ciclului exterior, deoarece nu avem nicio instruciune care s
"ias" din dou cicluri. Este de asemenea evident c ultimele dou comparaii sunt
complementare: dac una va fi adevrat cealalt va fi fals i invers. De aceea cel de-al
doilea ciclu poate s nceap cu mutarea elementului din cel de-al doilea subvector, cu
condiia ca primul ciclu s se fi terminat cu gsirea unui element mai mare n primul
subvector:

do
{
temp[k] = v[j] ;
j++;
k++;
if(j>d)
{
goto out;
}
}
while((v[i]>=v[j]));

Dar dup ce se execut o dat cel de-a! doilea ciclu i se ncheie cu gsirea unui
element mai mare dect primul element din primul subvector este clar care este elementul
care trebuie mutat. De aceea pentru a putea scrie cele dou cicluri simetric, ncepem cu
selectarea elementelor din cel de-al doilea subvector:

void combina3(int v[], int s, int m, int d)
{
int i = s;
int j = m + 1;
int *temp = new int[d - s + 1];
int k = 0;
while (v[i] >= vj]])
{
temp[k] = v[j];
j++;
k++;
if (j > d)
{
goto out;
}
}
while (true)
{
do
{
temp[k] = v[i];
i++;
k++;
if (i > m)
{
goto out;
}
}
while (v[i] < v[j]);
do
{
temp[k] = v[j];
j++;
k++;
if(j>d)
{
goto out;
}
}
while(v[i] >= v[j]);
}
out:
for ( ; i <= in; i++)
{
temp[k] = v[i];
k++;
}
for( ;j <=d;j++)
{
temp[k] = v[j]; '
k++;
}
memcpy(&v[s], temp, (d - s + 1) * sizeof(int));
delete temp;
}
In cazul cel mai favorabil, de exemplu cnd elementele din ce! de-al doilea subvector
sunt mai mici toate dect oricare element din primul subvector, avem 2 comparaii pentru a
muta fiecare element din cel de-al doilea subvector. Dup care avem cte o comparaie pentru
a muta un element din primul subvector. innd cont c fiecare subvector are n/2 elemente
ajungem la 3/2n comparaii. Dac elementele sunt distribuite astfel nct trebuie s lum cte
un element din fiecare subvector avem 2 comparaii pentru fiecare element, deci un total de
aproximativ 2n comparaii. Dar aceast implementare este puin cam lung i nestructurat,
folosind instruciunea goto. Dac revenim la prima variant vedem c defectul acesteia const
n aceea c dup ce se incrementeaz i sau j se verific dac nu s-au terminat ambii
subvectori n loc s se verifice numai subvectorul al crui cap a fost "ars".

Descrierea algoritmului cu revenire la prima varianta
Urmtorul algoritm primete vectorul v[st..dr] cu elementele din subvectorii v[st..m],
v[m+l..dr] ordonate cresctor i are ca efect combinarea celor subvectori astfei nct ntreg
vectorul, de la st la dr, s fie ordonate cresctor, folosind un vector temporar.
P1. Se efectueaz urmtoarele iniializri: i = st, j = m + 1 i k = 0.
P2. Dac v[i] >= v[j] se trece la pasul P7, altfel se trece la. pasul P3.
P3. Se efectueaz atribuirea temp[k] = v[i].
P4. Se incrementeaz k.
P5. Se incrementeaz i.
P6. Dac k > m se continu cu pasul P1l, altfel se continu cu pasul P2.
P7. Se efectueaz atribuirea temp[k] = v[j].
P8. Se incrementeaz k.
P9. Se incrementeaz j.
P10. Dac j > d se continu cu pasul P11, altfel se continu cu pasul P2.
P1l. Dac i > m se continu cu pasul P16, altfel se continu cu pasul P12.
P12. Se efectueaz atribuirea temp[k] = v[i].
P13. Se incrementeaz i.
P14. Se incrementeaz k.
P15. Se continu cu Pil.
P16. Dac j > dr se continu cu pasul P21, altfel se continu cu pasul P17.
P17. Se efectueaz atribuirea temp[k] = v[j].
P18. Se incrementeaz j.
P19. Se incrementeaz k.
P20. Se continu cu P16.
P21. Se copiaz coninutul vectorului temp n v, ncepnd cu adresa lui v[st] i algoritmul se
ncheie.

Descrierea algoritmului cu revenire la prima varianta in C
void combina4(int v[], int s, ini: m, ini: d)
{
int i = s; int j = m + 1;
int *temp = new int[d - s + 1];
int k = 0;
while (true)
{
if(v[i]<v[j])
{
temp[k] = v[i];
i++;
k++;
if(i>m)
{
break;
}
}
else
{
temp[k] = v[j];
k++;
if(j>d)
{
break;
}
}
}
for ( ; i <= m; i++)
{
temp[k] = v[i];
k++;
}
for (; j <= d; j++)
{
ternpjk] = v[j];
k++;
}
memcpy(&v[s], temp, (d - s + 1) * sizeof(int));
delete temp;
}
Este evident c pentru fiecare element mutat, atunci cnd ambii subvectori mai au
elemente, se efectueaz 2 comparaii, dup care fiecare element, se efectueaz o singur
comparaie. Se mut n primul ciclu ce! puin n/2 elemente i cel mult n - 1 de unde putem
obine numrul de comparaii pentru cazul cel mai favorabil i cel mai defavorabil. Atunci
cnd nu ne permitem alocarea unui vector temporar, putem interclasa cei doi subvectori ntr-o
manier asemntoare cu inseria direct:

Descrierea algoritmului cu interclasarea vectorilor asemanator insertiei directe
. Urmtorul algoritm primete vectorul v[st..dr] cu elementele din subvectorii v[st..m],
v[m+i..dr] ordonate cresctor i are ca efect combinarea celor subvectori astfel nct ntreg
vectorul, de la st la dr, s fie ordonate cresctor, folosind un vector temporar.
P1. Se iniializeaz i cu st i j cu m + 1.
P2. Dac j > dr algoritmul se ncheie, altfel se continu cu pasul P3.
P3. Dac v[i] >= v[j] se continu cu pasul P6, altfel se continu cu pasul P4.
P4. Se incrementeaz i.
P5. Se continu cu pasul P3.
P6. Dac i este egal cu j algoritmul se ncheie, altfel se continu cu pasul P7.
P7. Se atribuie lui temp valoarea v[j] i lui k valoarea j - 1.
P8. Dac avem k < i se sare la pasul P12, altfel se continu cu pasul P9.
P9. Se efectueaz atribuirea v[k + 1] = v[k].
P10. Se decrementeaz k.
P1l. Se continu cu pasul P8.
P12. Se efectueaz atribuirea v[i] = temp.
P13. Se incrementeaz i.
P14. Se incrementeaz j.
P15. Se continu cu pasul P2.

Se iau pe rnd elementele celui de-ai doilea subvector, ncepnd cu cel mai mic
element, i se caut poziia n care trebuie inserate n partea stng, innd cont de faptul c
toate elementele clin partea stng sunt ordonate cresctor. In momentul n care se gsete un
element din subvectorul drept care se afl deja pe poziia corect algoritmul se ncheie, Dac
elementul v[j] trebuie inserat pe o poziie i oarecare, mai nti i se face loc, deplasndu-se
elementele din intervalul [i, j - 1] cu o poziie spre dreapta, dup care are loc inserarea. Se
continu cu urmtorul element din subvectorul drept, poziia acestuia cutndu-se ncepnd
cu poziia clin dreapta celei pe care a avut oc ultima inserare.

Descrierea algoritmului cu interclasarea vectorilor asemanator insertiei directein C
void combina5(int v[], int s, int m, int d)
{
int i = s;
int j ;
int k;
int temp;
for (j = m + 1; j <= d; j++)
{
while (v[i] < v[j])
{
i++;
}
if(i==j)
{
break;
}
temp = v[j];
for(k = j- l;k>=i;k--)
{
v[k+l] = v[k];
}
v[i] = temp;
i++;
}
}
In cazul cel mai favorabil, cnd elementele din stnga sunt mai mici dect cel mai mic
element din dreapta avem n/2 + 2 comparaii i nici o deplasare. Dar dac este valabil
condiia inversa avem n/2(n/2 + 2) comparatii si n/2(n/2 + 1) deplasari.Timpul mediu este de
ordinul O(n
2
).
In final, trebuie s se in cont de faptul c adncimea arborelui de partiionare este
log
2
n i c pentru fiecare nivel trebuie s adugm costul operaiei de combinare. Deci, atunci
cnd putem folosi vectori temporari algoritmul are ordinul 0(nlog
2
n) i 0(n
2
log
2
n) n cazul
folosirii ultimei variante a algoritmului de interclasare.

2.2.7. Sortarea prin Numrare.
Algoritmul este foarte simplu: mai nti se determin poziia fiecrui element al
vectorului ntr-un vector sortat dup care se plaseaz elementele pe poziiile calculate ntr-un
vector temporar. Dun care se copiaz elementele din vectorul temporar la loc n vectorul
iniia!.

Descrierea algoritmului :
Dndu-se vectorul v cu n elemente, urmtorul algoritm rearanjeaz elementele
vectorului astfel nct ia final acestea s fie n ordine, v[0] v[l] ... v[n - 2] v[n 1].
P1. Se iniializeaz i cu 0.
P2. Dac i este egal cu n se continu cu P6, altfel se continu cu pasul P3.
P3. Se iniializeaz poziie[i] cu 0.
P4. Se incrementeaz i.
P5. Se continu cu pasul P2.
P6. Dac i este egal cu n - 1 se continu cu P14, altfel se continu cu pasul P7.
P7. Se iniializeaz j cu i + 1.
P8. Dac j este egal cu n se continu cu P12, altfel se continu cu pasul P9.
P9. Dac v[i] > v[j] se incrementeaz poziie[i], altfel se incrementeaz poziie[j],
P10. Se incrementeaz j.
P11. Se continu cu pasul P8.
P12. Se incrementeaz i.
P13. Se continu cu pasul P6.
P14. Se iniializeaz i cu 0.
P15. Dac i este egal cu n se continu cu P19, altfel se continu cu pasul P16.
P16. Se iniializeaz temp[poziie[i]] cu v[i].
P17. Se incrementeaz i.
P18. Se continu cu pasul P15.
P19. Se copiaz temp n v i algoritmul se ncheie.

Descrierea algoritmului in C :
void sortareNumarare(int v[], int n)
{
int i;
int j;
int *pozitie = new int[n];
int
*
temp = new int[n];
for (i = 0; i < n; i++)
{
Pozitie[i] = 0;
}
for (i = 0; i < n - 1; i++)
{
for (j = i + l;j <n;j++)
{
if(v[i]>v[j])
{
pozitie[i]++;
}
else
{
pozitie[j]++;
for (i = 0; i < n; i++)
{
temp[pozitie[i]] = v[i];
}
}
}
memcpy(v, temp, n * sizeof[int));
delete poziie;
delete temp;
}

Se compar fiecare dou elemente, prin urmare primul element se compar cu n - 1
elemente, al doilea element cu toate cele n - 2 elemente aflate n dreapta lui i aa mai
departe, n total avem n(n 1)/2 comparatii. Performanele algoritmului nu depind de
modul n care sunt aranjate elementele vectorului.

2.2.8. Sortarea prin Numrarea Distribuiilor,
Acest algoritm este asemntor cu sortarea prin numrare, dar se folosete n cazul n
care avem informaii suplimentare despre elementele vectorului, ca de exemplu faptul c sunt
numere ntregi n intervalul [0, k]. Dac numrul k este mult mai mic dect numrul total de
elemente este rentabil utilizarea urmtorului algoritm:

Descrierea algoritmului :.
Dndu-se vectorul v cu n elemente, elementele fiind numere ntregi din intervalul [0,
k], urmtorul algoritm rearanjeaz elementele vectorului astfel nct la final acestea s fie n
ordine, v[0] v[l] ... v[n -2] <v[n - ]].
P1. Se iniializeaz i cu 0.
P2. Dac i este mai mare dect k se trece la pasul P6, altfel se trece la pasul P3.
P3. Se iniializeaz apariii[i] cu 0.
P4. Se incrementeaz i.
P5. Se continu cu pasul P2.
P6. Se iniializeaz i cu 0.
P7. Dac i este egal cu n se trece la pasul P1l, altfel se trece la pasul P8.
P8. Se incrementeaz apariii[v[i]].
P9. Se incrementeaz i.
P10. Se continu cu pasul P7.
P11. Se decrementeaz apariii[0].
P12. Se iniializeaz i cu 1.
P13. Dac i este mai mare dect k se trece la pasul P17, altfel se trece la pasul P14.
P14, Se efectueaz atribuirea apariii[i] = apariii[i] + apariii[i - 1].
P15, Se incrementeaz i.
P16. Se continu cu pasul P13.
P!7. Se iniializeaz i cu 0.
P18. Dac i este egal cu n se trece la pasul P23, altfel se trece la pasul P19.
P19, Se efectueaz atribuirea temp[apariii[v[i]]] = v[i].
P20. Se decrementeaz apariii[v[i]].
P21. Se incrementeaz i.
P22. Se continu cu pasul P18.
P23. Se copiaz coninutul vectorului temp n vectorul v i algoritmul se ncheie.
.
Mai nti se iniializeaz elementele vectorului apariii cu 0. Apoi pentru fiecare
element al vectorului v se incrementeaz elementul corespunztor din vectorul apariii. In
urmtoarea etap, apariii[v[i]] va conine indexul pe care l va avea n vectorul sortat ultimul
element cu valoarea v[i]. De aceea, dup ce se efectueaz atribuirea temp[apariii[v[i]]] = v[i]
se decrementeaz apariii[v[i]], deoarece urmtorul element cu aceeai valoare va fi amplasat
n stnga.

Descrierea algoritmului in C :
void sortareNumai'areDistributii(int v[], ini n, int k)
{
int i;
int *apariii = new int[k + 1];
int *ternp = new int[n];
for (i = 0; i <= k; i++)
{
aparitii [i] = 0;
}
for(i =0; i < n; i++)
{
aparitii[v[i]]++;
}
aparitii[0]--;
for (i = 1; i <= k; i++)
{
aparitii[i] = aparitii[i] + aparitii[i - 1];
}
for(i = 0; i < n; i++)
{
temp[aparitii[v[i]]] = v[i];
aparitii[v[i]--;
}
memcpy(v, temp, n * sizeof(int));
delete temp;
delete apariii;
}
Algoritmul are un timp de execuie ele ordinul O(max(n, k + 1)).

Vous aimerez peut-être aussi