Sunteți pe pagina 1din 13

Clasificarea algoritmilor(strategii generale)

A. Algoritmi de sortare prin comparatii


1.Sortare prin interschimbare
2.Sortare prin insertie
Sortarea prin insertie directa si sortare prin insertie binara
Sortare prin metoda Shell
3.Sortare prin selectie
Selectie naiva
Selectie sistematica
B. Algoritmi de sortare prin distribuire
Sortarea cuvintelor
Distribuire prin segmentare
C.Algoritmi de sortare prin numarare
D.Sortare topologica
E.Algoritmi de sortare utilizand metoda Divide et impera
Sortarea prin interclasare
Sortarea rapida

Elemente fundamentale
Sortare -algoritmul prin care putem rearanja k elemente intr-o anumita
ordine (de exemplu: in ordine lexicografica, ordine crescatoare).
Fiecare algoritm de sortare are nevoie de un anumit spatiu si un anumit
timp pentru executarea algorimului. Pentru masurarea complexitatii vom
folosi notatia complexitatii O(n) (n reprezinta numarul de comparatii
ale algoritmului). Vom citi complexitate de n. De asemenea, vom
folosi o notatie asemanatoare pentru a masura consumul memoriei.

2. algoritmi de sortare. 2.1 Bubble Sort


Cazul mediu : O(N^2). Cazul defavorabil : O(N^2)
Memorie folosita : O(1). Stabil : DA
Sortare descrescatoare : a[i] < a[i+1]
Sortare crescatoare : a [i] > a[i+1]
Descriere :
Acesta metoda se rezuma la a compara fiecare element cu celelalte,
facandu-se interschimbarea daca elementul mai mare are indexul mai
mic. Este cea mai simpla metode de sortare si nu necesita cunoasterea
detaliata a limbajului de programare. Poate fi folosita cu succes de catre
incepatori.

-. Bubble sort este o metod de sortare simpl, eficient pentru un


numr mic de elemente (mai putin de 15), dar nu pentru tabele mari.
-. Nu necesita foarte multa memorie dar este de doua ori mai lenta decit
inswrction Sort in aproape orice situatie
-. Timpul de executie depinde de input, adic de ordinea initial al
elementelor.
-. Dac tabela este deja sortat e nevoie de un singur pas, adic N-1
comparri. n cazul cel mai nefavorabil sunt necesare N (N-1)/2
comparri si N (N-1)/2 interschimbri.
-. Performanta algoritmului n caz general este mai greu de analizat dar
este asemntor cazului nefavorabil. Complexitatea timpului al Bubble
sortului este O(N2).
BubbleSort nu foloseste alte structuri de date si din aceasta cauza este
recomandabil in cazurile cu putine elemente de sortat si in cazul in care
memoria este limitata.
Implementare :
void bubble(int a[],int n)
schimbat = 1;}
{ int i,schimbat,aux;
}while(schimbat); }
Do { schimbat = 0;
procedure BubbleSort;
for(i = 0; i < n-1; i++)
VAR i,j : TipIndex; x :
//parcurgem vectorul
TipElement;
if(a[i] < a[i+1]) //daca valoarea i
begin
din vectorul a este
for i:=2 to N do
//mai mica decat cea de pe
for j:=N downto i do
pozitia i+1
if a[j-1].cheie>a[j].cheie then
{ //interschimbare
begin
aux = a[i];
x:=a[j-1];
a[i] = a[i+1];
a[j-1]:=a[j];
a[i+1] = aux;
a[j]:=x
end; end; {BubbleSort}

2.2 Selection Sort


Cazul mediu : O(N^2) Cazul defavorabil : O(N^2)
Memorie folosita : O(1) Stabil : DA
Sortare descrescatoare : min < a[j]
Sortare crescatoare : min > a[j]

Descriere :
Selectia direct este una dintre cele mai simple metode de sortare si va l
ucra
foarte bine pentru tabele mici, fiecareelement (nregistrare), este mutat c
el mult o dat.. Implementarea algoritmului este simplu.Algoritmul
presupune ca la fiecare pas i sa se gaseasca elementul minim dintre
a[i+1], a[i+2]a[n] si se interschimba cu a[i].
Se cheltuie cel mai mult timp cu cutarea elementului minim din
partea nesortat a tabelei.Cutarea se face de la stnga la dreapta. Pe
parcursul fiecrui pas este necesar o interschimbare, deci numrul
interschimbrilor pentru N elemente este: N-1.
Implementare :
void selective(int a[],int n)
{ int i,aux,min,minat;
for(i = 0; i < n - 1;i++)
{ minat = i;
min = a[i];
for(j = i + 1;j < n;j++) //selectam minimul
//din vectorul ramas( de la i+1 la n)
{ if(min > a[j]) //sortare crescatoare
{ minat = j; //pozitia elementului minim
min = a[j]; } }
aux = a[i] ;
a[i] = a[minat]; //interschimbare
a[minat] = aux; } }

Insertion Sort
Cazul mediu : O(N^2) Cazul defavorabil : O(N^2)
Memorie folosita : O(1) Stabil : DA
Sortare descrescatoare : j > 0 && a[j - 1] < a[j]
Sortare crescatoare : j > 0 && a[j - 1] > a[j]
Insertia direct apartine familiei de tehnici de sortare care se bazeaz pe
metoda "juctorului de bridge". Este un algoritm aproape la fel de
simplu ca Selection sort, dar poate mai flexibil. Considerm elementele
A[1]...A[i-1] fiind sortate, inserm elementul A[i] n locul ce i revine.
Fiind dat o tabel A cu N elemente nesortate, parcurgem tabela si le ins

ermfiecare element n locul propriu ntrecelelalte elemente considerate


sortate. Pentru fiecare i = 2..N , elementele A[1]A[i] sunt sortate prin i
nserarea lui A[i] ntrelista elementelor sortate: A[1]A[i1]. Elementele aflate n stnga indexului sunt n ordine sortat dar nu
sunt n pozitia lorfinal. Tabela este sortat complect cnd indexul ajun
ge la captul drept al tabelei.
Insertion sort este un algoritm de sortare simplu,
liniar: O(N) pentru tabele care contin N elemente aproape sortate.
Timpul de executie al algoritmului depinde de numrul
inversrilor, deci de ordinea initial al elementelor. n caz general sunt
necesare N 2 /4 comparatii si interschimbri, N 2 /8 deci ordinea
magnitudinii este O(N 2).
Implementare :
void insertion(int a[], int n)
{ int i, j, aux;
for (i = 1; i < n; i++)
{ j = i;
while (j > 0 && a[j - 1] > a[j])
{ aux = a[j]; a[j] = a[j - 1];
a[j--] = aux; } } }

2.4 Shell Sort


Cazul mediu : Cazul defavorabil : O(N * log^2 N)
Memorie folosita : O(1)
Stabil : NU
Sortare descrescatoare : j >= h && a[j-h] < v
Sortare crescatoare : j >= h && a[j-h] > v
Descriere
Principiu: reprezinta o perfectionare a metodei de sortare prin insertie.
Se alege o secventa de numere naturale h1, h2,..., ht numite incrementi,
care satisfac conditiile: ht=1 si h(i+1) < hi pentru i=1,t-1
Se realizeaza t treceri asupra tabloului, la fiecare trecere i luindu-se in
considerare elementele a[1], a[1+hi], a[1+2*hi] etc. Aceste elemente se
sorteaza aplicind metoda insertiei, cu utilizarea fanionului. S-a
demonstrat ca eficienta algoritmului creste daca valorile incrementilor

nu sint puteri ale lui 2. Pentru a putea folosi tehnica fanionului la aceasta
metoda este necesar sa se prelungeasca tabloul a spre stinga cu inca h1
elemente.
Implementarea algoritmului in Pascal:
procedure ShellSort;
for i:=k+1 to N do begin
const h1=...;
j:=i-k;
var i,j,k,s : -h1+1..N; x :
if s=0 then s:=-k;
TipElement;
inc(s);
m : 1..t;
a[s]:=a[i];
h : ARRAY[1..t] OF Integer;
while a[s].cheie < a[j].cheie do
a : ARRAY[-h1+1..N] OF
begin
TipElement;
a[j+k]:=a[j]; j:=j-k
begin
end;
{initializarea elementelor lui h}
a[j+k]:=a[s];
for m:=1 to t do begin
end; end; end; {ShellSort}
k:=h[m]; s:=-k; {pozitia
fanionului}
Merge Sort
Algoritmul de sortare prin interclasare se bazeaz pe urmtoarea idee: pe
ntru asorta o tabel cu N elemente l mprtimn dou tabele pe care le s
ortez separat si leintrclasm. Este o metod de sortare care foloseste strat
egia de baz "divide etimpera",conform creia problema se descompune
n alte dou subprobleme de acelasi tip si duprezolvarea lor rezultatele
se combin. Algoritmul sorteaz elementele n ordine
cresctoare.Tabelul se imparte in n/2, dupa aceea tabelele se impart in
jumatate, tot asa pana cand tabelele formate au mai putin sau cel mult
de k elemente(in cazul nostru k=2-este cel mai usor sa compari 2
elemente).
Cazul mediu : O(N log N) Cazul defavorabil : O(N log N)
Memorie folosita : O(N)
Stabil : DA
Sortare descrescatoare : b[i] >= a[j]
Sortare crescatoare : b[i] <= a[j]
Descriere :
In cazul sortarii prin interclasare vectorii care se interclaseaza sunt doua
secvente ordonate din acelasi vector.
Sortarea prin interclasare utilizeaza metoda Divide et Impera:

- se imparte vectorul in secvente din ce in ce mai mici., astfel incat


fiecare secventa sa fie ordonata la un moment dat si interclasata cu o alta
secventa din vector corespunzatoare.
- practic interclasarea va incepe cand se ajunge la o secventa formata din
doua elemente.
Aceasta odata ordonata se va interclasa cu o alta corespunzatoare. Cele
doua secvente vor alcatui in subsir ordonat din vector mai mare care la
randul lui se va interclasa cu subsirulcorespunzator s.a.m.d.
Implementare :
void mergesort(int a[],int st, int
a[k++] = b[i++];
m, int dr) { int b[100];
else a[k++] = a[j++];
int i, j, k; i = 0; j = st;
// copiem elementele ramase daca
// copiem prima jumatate a
mai exista
vectorului a in b
while (k < j)
while (j <= m)
a[k++] = b[i++]; }
b[i++] = a[j++];
void merge(int a[],int st, int dr)
i = 0; k = st;
{ if (st < dr)
// copiem inapoi cel mai mare
{ int m = (st+dr)/2;
element la fiecare pas
merge(a,st, m);
while (k < j && j <= dr)
merge(a,m+1, dr);
if (b[i] <= a[j])
mergesort(a,st, m, dr); } }

Sortarea prin metoda ansamblelor (heapsort)


Principiu: se numeste ansamblu (heap) a secventa de chei h1, h2,..., hn
care satisfac conditiile: hi <= h2i si hi <= h2i+1 i=1,N/2.
Se aduce tabloul la forma unui ansamblu, adica pentru orice i,j, k din
intervalul [1,N], unde j=2*i si k=2*i+1, sa avem a[i].cheie<=a[j].cheie si
a[i].cheie<=a[k].cheie (*) Se observa ca in acest caz a[1] este elementul
cu cheia minima in tablou. Se interschimba elementele a[1] si a[N] si se
aduce subtabloul a[1],...,a[N-1] la forma de ansamblu, apoi se
interschimba elementele a[1] si a[N-1] si se aduce subtabloul
a[1],...,a[N-2] la forma de ansamblu s.a.m.d. In final rezulta tabloul
ordonat invers. Daca se schimba sensul relatiilor in conditiile (*) atunci
se obtine o ordonare directa a tabloului (a[1] va fi elementul cu cheia
maxima).

Aducerea unui tablou la forma de ansamblu se bazeaza pe faptul ca


subtabloul a[N/2+1],...,a[N] este deja un ansamblu (nu exista indicii j si
k definiti ca mai sus). Acest subtablou se va extinde mereu spre stinga
cu cite un element al tabloului, pina cind se ajunge la a[1]. Elementul
adaugat va fi glisat astfel incit subtabloul extins sa devina ansamblu.
Implementarea algoritmului in Pascal:
procedure HeapSort;
{deplasare}="" {heapsort}="
VAR s,d : TipIndex; x :
" {constructie="" ansamblu}="
TipElement;
" s:="(N" div="" 2)="
procedure Deplasare(s,d :
" +1;="" d:="N;" while="" s="">
TipIndex);
1 do begin
VAR i,j : TipIndex; ret : Boolean;
s:=s-1;
begin {Deplasare}
Deplasare(s,N);
i:=s; j:=2*i; x:=a[i]; ret:=False;
end;
{sortare}
while (j<=d) and (not ret) do
while d > 1 do begin
begin
x:=a[1]; a[1]:=a[d]; a[d]:=x;
if j<="" a[j+1].cheie="" j:="j+1;
d:=d-1;
" x.cheie="" begin="" a[i]:="a[j];
Deplasare(1,d)
" i:="j;" end="" else=""
end end; {HeapSort}
ret:="True" end;=""
Procedura Deplasare(s,d) realizeaza glisarea elementului a[s] astfel ca
subtabloul a[s],...,a[d] (s
Timpul de executie al sortarii este O(N*log N).
Implementare in C++:
void swap(int a[],int i,int j)
{ int aux = a[i];
a[i] = a[j];
a[j] = aux; }
void downheap(int a[],int v,int
n)
{ int w = 2 * v + 1; // primul
descendent al lui v
while (w<n)
{ if (w+1<n) // mai exista unul?

if (a[w+1]>a[w]) w++;
//crescator
// w este decendentul lui v
if (a[v]>=a[w]) return;
//crescator
swap(a,v, w); // interschimbam v
cu w
v = w; // continuam
w = 2 * v + 1; } }
void heapsort(int a[],int n)

{ for (int v = n/2-1; v >= 0; v--)


//creem heap`ul
downheap (a,v,n);
while (n>1)

{ n--;
swap(a,0, n);
downheap (a,0,n); } }

Sortarea prin partitionare (quicksort)


n practic algoritmul de sortare cel mai rapid
este Quicksort numit sortare rapid, care foloseste partitionarea ca idee
de baz.
-. Este mai rapid dect orice metod de sortare simpl, se execut bine
pentru fisiere sau tabele mari, dar ineficient pentru cele mici.
-. Strategia de baz folosit este "divide et impera", pentru c este mai
usor de sortat dou tabele mici, dect una mare.
-. Algoritmul este usor de implementat, lucreaz destul de bine n
diferite situatii si consum mai putine resurse dect orice alt metod de
sortare n multe situatii.
-. Necesit numai n jur de NlogN operati n cazul general pentru a
sorta N elemente.
Metoda QuickSort presupune gasirea pozitiei finale pe care o ocupa
elemenetul de pe prima pozitie comparandu l cu elementele din
cealalta partitie a tabelului, acest algoritm realizandu-se pana cand
partitia are 1 element.
Potrivit algoritmului, fiecare element este comparat cu pivoul,
adic operatiunea este de O(N), tabela este divizat n dou prti,
fiecare parte este divizat iarsi n dou. Dac fiecare parte este
mprtit aproximativ n jumtate, va rezulta log2N mprtiri. Deci
timpul de executie al Quicksortului n caz mediu este de O(N log2 N),
iar n caz nefavorabil O(N2) .
Quicksort este o metod bun n caz general, dar nu si n caz
nefavorabil cnd este preferabil folosirea a 3 indicii de impartire.
Randomizarea este o idee important si folositoare, o unealt general
pentru a mbuntti algoritmul. Quicksort este sensibil la ordinea datelor

de intrare. Nu este o metod stabil.


Dezavantajul algoritmului este c, e recursiv. Necesit n jur de N 2
de operatii n caz nefavorabil. Este fragil, o simpl greseal n
implementare poate cauza o executare gresit pentru anumite fisiere.
quicksort.cpp
procedure QuickSort_Recursiv;
x,w:TipElement;
VAR m:TipIndex;
is : 0..m;
procedure Sortare(s,d:TipIndex);
Stiva : ARRAY[1..m] OF
VAR i,j:TipIndex;
NodStiva;
x,w:TipElement;
begin
begin
is:=1; Stiva[1].s:=1;
i:=s; j:=d; x:=a[(s+d) div 2];
Stiva[1].d:=N;
repeat
repeat
while a[i].cheiex.cheie do j:=j-1;
{extragere limite partiale din
if i<=j then begin
virful stivei}
w:=a[i]; a[i]:=a[j]; a[j]:=w;
s:=Stiva[is].s; d:=Stiva[is].d;
i:=i+1; j:=j-1 end
is:=is-1;
until i>j;
repeat
if si then Sortare(i,d);
{partitionarea sirului a[s],...,a[d]}
end; {Sortare}
i:=s; j:=d; x:=a[(s+d) div 2];
begin m:=1;
repeat
Sortare(m,N)
while a[i].cheiex.cheie do j:=j-1;
end; {QuickSort_Recursiv}
if i<=j then begin
procedure QuickSort_Nerecursiv;
w:=a[i]; a[i]:=a[j]; a[j]:=w;
CONST m=12; {dimensiunea
i:=i+1; j:=j-1 end
stivei}
until i>j;
TYPE NodStiva=RECORD
if i=d
s,d:TipIndex; end;
until is=0
VAR i,j,s,d:TipIndex;
end; {QuickSort_Nerecursiv}
In cazul algoritmului nerecursiv este necesara o stiva care memoreaza
limitele uneia dintre cele doua partitii care apar la o trecere, si anume
limitele partitiei care este tratata a doua (aici, partitia dreapta). Timpul
de executie este O(N* log N) si O(N*N),in cazul cel mai defavorabil.
Implementare in C++:
void qSort(int vector[],int st,int dr)
{ int temp,min,max,mijl;
mijl = vector[st+(dr-st)/2]; //luam mijlocul intervalului

min = st; max = dr;


do { while(vector[min] < mijl) min++;
while(vector[max] > mijl) max--;
if(min <= max) //interschimbare
{ temp = vector[min];
vector[min++] = vector[max];
vector[max--] = temp; }
}while(min <= max); //la fiecare pas sortam "mai bine" intervalul st-dr
//cand numai avem ce face schimbam intervalul
if(st < max) qSort(vector,st,max); //crescator
if(dr > min) qSort(vector,min,dr); //crescator }

Implementri cu ajutorul STL


Pentru a usura munca programatorului si implicit a imparti timpul alocat
unei probleme in alte
directii librariile standard ofera ajutor pentru a implementa cativa dintre
algoritmii de mai sus.
In libraria standard a limbajului C este implementata o varianta naiva de
Quicksort,iar STL-ul
ofera programatorilor C++ o implementare a algoritmului Introsort, cat
si functiile make_heap si
sort_heap, pentru a putea implementa usor Heapsort.

3.1 Heap Sort


Implementare :
#include <algorithm>
#include <vector>
#include <cstdio>
using namespace std;
vector<int> v;
int main()
{ int i, x, n;
freopen("heapsort.in","r",stdin;
freopen("heapsort.out","w",stdou
t);

scanf("%d",&n);
for(i = 0; i < n; i++ )
{ scanf("%d",&x);
v.push_back(x); }
make_heap(v.begin(),v.end());
sort_heap(v.begin(),v.end());
for(i = 0; i < n; i++)
{ printf("%d ",v[i]); }
return 0; }

3.2 Quick Sort


Implementare :
#include <stdlib.h>
#include <stdio.h>

#define MAX_N 10000


int n, v[MAX_N];

int cmp(const void* x,const


scanf("%d",v+i);
void *y);
qsort(v,n,sizeof(v[0]),cmp);
int main(int argc, char *argv[])
for(i = 0; i < n; i++)
{ int i;
{ printf("%d ",v[i]); }
freopen("qsort.in","r",stdin);
return 0; }
freopen("qsort.out","w",stdout);
int cmp(const void*x, const
scanf("%d",&n);
void *y )
for(i = 0; i < n; i++ )
{ return *(int*)x - *(int*)y; }
3.3 Intro Sort
Cazul mediu : O(N log N)
Cazul defavorabil : O(N log N)
Memorie folosita : O(log N)
Stabil : DA
Descriere :
Introsort sau introspective sort este una dintre cele mai bune metode de
sortare a unuivector. Ea se bazeaza pe doi algoritmi studiati
precedent(quick sort si heap sort).Algoritmulincepe sa lucreze cu
QuickSort ,dar cand recursivitatea atinge o anumita adancime(bazata pe
numarul elementelor ce urmeaza sa fie sortate) algoritmul continua
sortarea cu ajutorul metodeiHeapSort.Optimizarea adusa QuickSort`ului
in aceasta situatie va fi alegerea pivotului pe baza"median of 3" valorilor
: st,dr,mijl.
Implementare :
freopen("introsort.out","w",stdou
#include <algorithm>
t);
#include <vector>
scanf("%d",&n);
#include <cstdio>
for(i = 0; i < n; i++ )
using namespace std;
{ scanf("%d",&x);
vector<int> v;
v.push_back(x); }
int main()
sort(v.begin(),v.end());
{ int i, x, n;
for(i = 0; i < n; i++)
freopen("introsort.in","r",stdin);
{ printf("%d ",v[i]); }
return 0; }

4. LSD Radix Sort(Least significant digit radix sort)


4.1 Descriere
Cazul mediu : O(N * k) Cazul defavorabil : O(N * k)
Memorie folosita : O(N) Stabil : DA
k = lungimea medie a fiecarei chei(numar,cuvant)
Descriere :

LSD Radix Sort este una dintre cele mai rapide metode de
sortare.Aceasta se bazeaza pe sortarea in functie de cea mai
nesemnificativa cifra(least significant digit).
4.2 Algoritmul
Deoarece Radix Sort este un algoritm hibrid, ce nu are la baza o tehnica
de comparare fiecare element se numeste cheie.Valorile sunt gandite
ca siruri de caractere si procesate pe
biti. Algoritmul sorteaza cheile dupa urmatoarea regula : cheile de
lungime mai mica sunt
asezate in fata celor de lungime mai mare,iar cele de aceeasi lungime
sunt asezate in ordine
lexicografica.
LSD Radix Sort poate sorta un vector cu valori intregi sau de tip string in
ordine lexicografica.Deoarece fiecare numar/cuvant este considerat un
sir de caractere, procesarea incepe de la cea mai nesemnificativa dintre
valorile sirului de caractere.Astfel valorile la pasul k sunt
comparate,sortate iar cele ce au valori egale sunt lasate in pace pentru a
fi evaluate ulterior la un pas k+i .
4.3 Implementare
#define COUNT_N 256
++count[(a[i]>>byte)&Lm];
#define BYTE 8
for(i = 0;i < COUNT_N; ++i)
#define N_MAX 1000000
ind[i] = ind[i-1] + count[i-1];
int
for(i = 0; i < n; ++i)
a[N_MAX],b[N_MAX],count[C
b[ind[(a[i]>>byte)&Lm]++] =
OUNT_N],ind[COUNT_N];
a[i];}
void rad(int *a,int *b,int byte,int
void radix(int *a,int n)
n)
{ rad(a,b,0 ,n);
{ memset(count,0,sizeof(count));
rad(b,a, BYTE,n);
int i,Lm = COUNT_N - 1;
rad(a,b,2*BYTE,n);
for(i = 0; i < n; ++i)
rad(b,a,3*BYTE,n); }

4.4 Avantaje i dezavantaje


Acest algoritm nu este perfect suferind la capitolul memorie alocata, ce
este aproape dubla fata de QuickSort ,dar poate reprezenta asul din
maneca cand nu se tine cont de aceasta ci doar de viteza algoritmului.
LSD Radix Sort poate fi o alternativa pentru algoritmii de sortare
clasici , in special in momentele in care dependenta de o viteza cat mai
ridicata de sortare este in primul plan iar timpul pentru o implementare
nu este presant.
Avantaje :
- Viteza vizibil imbunatatita
- Posibilitatea de a sorta diferite tipuri de valori(cuvinte,numere etc.)
Dezavantaje :
- Implementarea dificila
- Consumul de memorie alocat ridicat