Sunteți pe pagina 1din 117

1.

mergesort
#include <iostream>
#include<iomanip>
using namespace std;
int a[100],n;
void mijloc(int s, int d, int &m)
{
m=(s+d)/2;
}
void refa(int s, int d, int m)
{
int i=s, j=m+1, k=1, b[100];
while(i<=m&&j<=d)
{
if(a[i]>a[j])
{
b[k]=a[j]; j++;
}
else
{
b[k]=a[i];
i++;
}
k++;
}
while(i<=m)
{
b[k]=a[i];
k++;
i++;
}
while(j<=d)
{
b[k]=a[j];
k++;
j++;
}
k=1;
for(i=s;i<=d;i++,k++)
a[i]=b[k];
}
void merge(int s, int d)

{
int m;
if(s<d)
{
mijloc(s,d,m);
merge(s,m);
merge(m+1,d);
refa(s,d,m);
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
merge(1,n);
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
cout<<setprecision(n,3);
return 0;
}
2. quicksort
#include <iostream>
using namespace std;
int a[10];
void schimba( int &x, int &y)
{
int aux=x;
x=y;
y=aux;
}
void pivot(int s, int d, int &m)
{
int i=s,j=d, pi=0,pj=1;
while(i<j)
{

if(a[i]>a[j])
{
schimba(a[i],a[j]);
schimba(pi,pj);
}
i=i+pi;
j=j-pj;
}
m=i;
}
void quick( int s, int d)
{
int m;
if(s<d)
{
pivot(s,d,m);
quick(s,m-1);
quick(m+1,d);
}
}
int main()
{
int n,i;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
quick(1,n);
for( int i=1;i<=n;i++)
cout<<a[i]<<" ";
return 0;
}
3. pliere vector
#include <iostream>
using namespace std;
int a[100],n;
void pliere(int i, int j)
{
int m;
if(i==j) cout<<a[i]<<" ";

else
{
m=(i+j)/2;
if((j-i+1)%2==0)
{
pliere(i,m);
pliere(m+1,j);
}
else{
pliere(i,m-1);
pliere(m+1,j);
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
pliere(1,n);
return 0;
}
4. sortari
Lucarea de laborator nr. 7
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 Ri si Ri+1 sa existe una dintre relatiile urmatoare
intre cheile de sortare : Ki< Ki+1 sau Ki > Ki+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 ai < ai+1, respectiv ai > ai+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 dintrun 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
log2n, 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 2n,
notat cu
O(n*log2n). 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 2n).

Sortarea prin inserie Direct,


Acest algoritm este folosit de juctorii de cri carei aranjeaz crile pe msur ce le primesc, insernclule 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 pi 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 1
5
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 =
2x+1 + 1, cu 0 < s < t= log2n.
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 deal 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(n2).
In final, trebuie s se in cont de faptul c
adncimea arborelui de partiionare este log2n i c

pentru fiecare nivel trebuie s adugm costul operaiei


de combinare. Deci, atunci cnd putem folosi vectori
temporari algoritmul are ordinul 0(nlog 2n) i 0(n2log2n)
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)).
Lucarea de laborator nr. 7
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 Ri si Ri+1 sa existe una dintre relatiile urmatoare
intre cheile de sortare : Ki< Ki+1 sau Ki > Ki+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 ai < ai+1, respectiv ai > ai+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 dintrun 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
log2n, 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 2n,
notat cu
O(n*log2n). 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 2n).
Sortarea prin inserie Direct,
Acest algoritm este folosit de juctorii de cri carei aranjeaz crile pe msur ce le primesc, insernclule 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 pi 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 1
5
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 =
2x+1 + 1, cu 0 < s < t= log2n.

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 deal 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
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
continu cu pasul P2.
P1l. Dac i > m se continu cu pasul P16, altfel
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
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
ncepnd cu adresa lui v[st] i algoritmul se ncheie.

se

se
se

se

v,

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
asemanator insertiei directein C
void combina5(int v[], int s, int m, int d)
{
int i = s;
int j ;
int k;

vectorilor

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(n2).
In final, trebuie s se in cont de faptul c
adncimea arborelui de partiionare este log2n i c
pentru fiecare nivel trebuie s adugm costul operaiei
de combinare. Deci, atunci cnd putem folosi vectori
temporari algoritmul are ordinul 0(nlog 2n) i 0(n2log2n)
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)).

S-ar putea să vă placă și