Documente Academic
Documente Profesional
Documente Cultură
Sortarea ese o operatie foarte des întilnîtă în rezolvarea unei probleme prin metode algoritmice. Din
acest motiv algoritmii de sortare constituie o clasa extrem de importantă care merită o atentie
specială iar o analiză a celor mai cunoscuti algoritmi de sortare este utilă si necesară.
Algoritmul Insertion Sort considera ca în pasul k, elementele A[1÷k-1] sunt sortate, iar elementul k
va fi inserat, astfel încât, dupa aceasta inserare, primele elemente A[ ÷k] sa fie sortate.
Pentru a realiza inserarea elementului k în secventa A[1÷k-1], aceasta presupune:
· memorarea elementului intr-o varibila temporara;
· deplasarea tuturor elementelor din vectorul A[1÷k-1] care sunt mai mari decât A[k], cu o
poziie la dreapta (aceasta presupune o parcurgere de la dreapta la stânga);
· plasarea lui A[k] în locul ultimului element deplasat.
insertion_sort(A,n)
{
for (k=2; k<= n; k++)
{
temp = A[k];
i=k-1;
while (i>=1 && A[i] > temp)
{
A[i+1] = A[i];
i=i-1;
}
A[i+1] = temp;
}
}
Complexitatea:
Cazul cel mai dafavorabil: situatia în care deplasarea (la dreapta cu o pozitie în vederea înserarii) se
face pâna la începutul vectorului, adica sirul este ordonat descrescator.
Exprimarea timpului de lucru:
T(n) = 3·(n - 1) + (1 + 2 + 3+ ... + n - 1) = 3(n-1) + 3n (n - 1)/2
Rezulta complexitatea: T(n) = O(n2) ¾ functie polinomiala de gradul II.
Observatie: Când avem mai multe bucle imbricate, termenii buclei celei mai interioare dau gradul
polinomului egal cu gradul algoritmului.
1
Buble Sort (sortare prin interschimbare)
Buble_sort (A,n)
// A[1..n] - seceventa de sortat
{
flag=1;
k=n;
while (flag != 0 && k >= 1)
{
k=k-1;
flag=0;
for (i=1; i<=k; i++)
if ( A[i] > A[i+1] )
{
interchange ( A[i], A[i+1] );
flag=1;
}
}
}
Exemplu :
h=4 1 5 7 8 3 12 9 4 12
|____________________________|_____________________________|
|____________________________|
|____________________________|
|____________________________|
h=3 1 5 7 8 3 12 9 4 12
|_____________________|_____________________|
|_____________________|_____________________|
|_____________________|_____________________|
h=1 1 5 7 8 3 12 9 4 12
|_______|_______|_______|_______|_______|______|_______|_______|
Shell_sort (A,n,h,t);
2
// A[1..n] - seceventa de sortat
// h[1..t] - incrementii h t > ht-1 > … >h1=1
{
for ( s=t; s>=1; s--)
{
h=h[s];
for ( j=h+1; j<=n; j++)
{
x=A[j];
i=j-h;
while (i>0 && x <A[i] )
{
L[i+h]=L[i];
i=i-h;
}
L[i+h]=x;
}
}
}
Radix Sort
Se presupune ca cheile de sortare sint numere zecimale. Fiecare element din secventa de sortat are k
cifre d1d2…dk
radix_sort (A,n,k)
// se preupune ca numerele zecimale sint reprezentate in baza d<=10
// seceventa se afla intr-o coada globala gq unde q[i], i=1,…,k sint cozi
{
for ( i=1; i<=d; i++ )
q[I]=F;
for ( i=k; i>=1; i-- )
{
while ( ! isempty(gq) )
{
x=del(gq);
d[i]=cifra i din x;
add (q[d[i]],x);
}
for ( i=1; i<=d; i++ )
while ( ! isempty(q[i]) ) //adauga coada q[i] la cooda globala gq
add (gq,del(q[i])
}
for ( i=1; i<=n; i++ )
x[i]=del[gq];
}
Complexitatea: O(nk)
Heap_Sort
Definitie:
Se numeste arbore heap un arbore binar T = (V, E) cu urmatoarele proprietati:
1) $ functia key : V ® R care asociaza fiecarui nod o cheie.
2) " un nod v Î V cu degree(v) > 0 (nu este nod terminal), atunci:
key(v) > key(left_child(v)), daca $ left_child(v)
key(v) > key(right_child(v)), daca $ right_child(v)
(Pentru fiecare nod din arbore, cheia nodului este mai mare decât cheile descendentilor).
3
Observatie: De obicei functia cheie reprezinta selectia unui subcâmp din câmpul de date memorate în
nod.
Generare Heap
heap_gen_1 (A,V, n)
// A[1..n] - seceventa de sortat
// V ¾ vectorul ce contine reprezentarea heap-ului;
// N ¾ numarul de noduri din heap,
{
N = 1 //se considera pentru început un heap cu un singurelement,
//dupa care toate celelalte elemente vor fi inserate în acest heap
for ( i = 2; i <= n; i++ )
insert(V, N, A[i]);
}
insert(V, N, a)
// V ¾ vectorul ce contine reprezentarea implicita a heap-ului;
// N ¾ numarul de noduri din heap,
// ambele sunt plasate prin referinta (functia insert le poate modifica);
// a ¾ atomul de inserat;
// 1) In reprezentarea implicita: V [N + 1] = a ; N = N + 1
// În continuare se reorganizeaza structura arborelui astfel încît sa-si pastreze structura de heap.
// 2) Se utilizeaza interschimbarile. Comparatii:
// Se iau 2 indici: child = N si
// parent = [N/2]
// Se compară V[child] cu V[parent]
// Interschimbare daca V[child] nu este mai mic decât V[parent]
// 3) Înaintare în sus: child = parent
// parent = [child/2]
// 4) Se reia pasul 2) pâna când nu se mai face interschimbarea.
{
N = N+1;
V[N] = a ;
child = N ;
parent = [N/2] ;
while (parent £ 1)
{
if key(V [child]) > key(V [parent])
{
interchange (V [child],V [parent]);
child = parent;
parent = [child/2];
}
else break; // se paraseste bucla Û parent = 0
}
}
Complexitatea:
Complexitatea operatiei insert:
4
În cazul cel mai defavorabil se parcurge o ramura care leaga un nod terminal de radacina. Rezulta,
complexitatea este data de adâncimea arborelui. Daca N este numarul de noduri din arbore, 2 k £ N £
2k+1 , si adâncimea arborelui este k+1.
Cazul cel mai defavorabil este situatia în care la fiecare inserare se parcurge o ramura completa. De
fiecare data inserarea unui element se face adaugând un nod la ultimul nivel. Pentru nivelul 2 sunt
doua noduri. La inserarea lor se va face cel mult o retrogradare (comparatie).
k 1 k 1 k 1 k 1
T (n) 2 i 2 i i 2 i i 2 i 1 i 2 i
i 1 i 1 i 1 i 1
k 1
1 2 2 2 3 2 ...( k 2) 2
2 3 4
( k 1) 2 k 1 2 1 2 2 2 3 2 3 ...( k 1) 2 k 1
k 1 k 1
2 ( k 1) 2 k 2 i ( k 1) 2 k 2 2 0 2 1 2 i
i 2 i 0
( k 1) 2 1 (2 1) ( k 2) 2 2
k k k
Rezulta: T (n) ( k 2) 2 k 2 ( k 2) (2 k 1) k 2 2 n ( k 2) k
iar: k log 2 (n 1) ,
din n 2k 1
Rezulta: T (n) n (log 2 (n 1) 2) log 2 (n 1)
------------------------
5
termen dominant
Construim heap-ul de jos în sus (de la dreapta spre stânga). Cele mai multe noduri sunt la baza, doar
nodurile din vârf parcurg drumul cel mai lung.
II
noduri terminale
heap_gen_2 (A,V, n)
// A[1..n] - seceventa de sortat
// V ¾ vectorul ce contine reprezentarea heap-ului;
{
for (i = 1; i <= n, i++)
V[i]=A[i];
for (i = [n/2]; i >= 1; i-- )
retrogradare(V,n, i);
}
retrogradare(V, n, i)
{
parent = i ;
child = 2*i ; // fiu stânga al lui i
while (child £ n)
{
6
if ( child+1 £ n && key(V[child+1]) > key(V[child] )
child = child + 1 ;
if key(V[parent]) < key(V[child])
{
interchange(V[parent], V[child]);
parent = child ;
child = 2*parent ;
}
else break;
}
}
Complexitatea
Fie un arbore complet cu n = 2k - 1. Cazul cel mai defavorabil este situatia în care la fiecare
retrogradare se parcurg toate nivelele:
k 1
Se aduna, si rezulta: T ( n) ( k i ) 2i 1
i 1
k 2 k 2
T ( n) ( k i ) 2 i ( k i ) 2 i 1 ( k 1) 2 1 ( k 2) 2 2 ( k 3) 2 3 ...3 2 k 3 2 2 k 2
i 1 i 1
k 3 k 3
( k 1) 2 ( k 2) 2 ( k 3) 2 ...2 2
0 1 2 k 3
22 k 2
( k 1) 2 2
1 k 1
( k 1) 2 2 1
0
i 1 i 0
k 1 k 2 k 2 k 2
2 2 2 ( k 1) 2 (2 1) k 1 3 2 k 1
Rezulta: T ( n ) 3 2 k 2 k 1 3 ( 2 k 1) k 1
T ( n ) 3 n log2 ( n 1) 1
-------
termen dominant
heap_sort (A,n)
7
// A[1..n] - seceventa de sortat
{
heap_gen(A, V, n); N = n;
for ( i = n; i >= 2; i-- )
{
N=I;
A[i] = remove(V, N) ;
}
}
max min
Procdura remove
remove(V, N)
// V ¾ vectorul ce contine reprezentarea implicita a heapu-lui;
// N ¾ numarul de noduri din heap
// ambele sunt plasate prin referinta (functia remove le poate modifica);
// se scoate elementul cel mai mare care este radacina heap-ului; se initializeaza cei 2 indici;
// se reorganizeaza structura arborilor: se ia ultimul nod de pe nivelul incomplet si-l aduc în nodul
// radacina, si aceasta valoare va fi retrogradata pîna când structura heap-ului este realizata.
// parent = max(parent, lchild, rchild).
// Exista trei cazuri:
// 1. conditia este îndeplinita deodata;
// 2. max este în stânga Þ retrogradarea se face în stânga;
// 3. max este în dreapta Þ retrogradarea se face în dreapta.
{
a = V[1];
V[1] = V[N];
N = N-1;
parent = 1;
child = 2;
while (child £ N)
{
if child+1 £ N and key(V[child+1]) > key(V[child])
child= child+1;
if key (V[parent]) < key(V[child])
{
interchange(V[parent], V[child]);
parent= child;
child= 2*parent;
}
else break;
}
return(a);
}
8
Complexitatea algoritmului Heap_Sort_2 este determinata de functiile remove ce nu pot fi aduse la
complexitate < O(log n). Astfel: Heap_Sort_2 = O(n) + O(n·log n)
---------------
termen ce determina complexitatea