Heapsort.
Costuri
2015
Algoritmul de sortare Heapsort
In acest capitol se prezinta un alt algoritm de sortare: HeapSort.
Heapsort foloseste o structura de date, pe care o vom numi heap
(ansamblu), structura ce permite extragerea maximului/minimului
rapid (in timp logaritmic).
Heapsort va fi un algoritm de sortare bazat pe selectia
maximului/minimului, cu o performanta O(n lg n).
Heaps
O structura de date de tip heap/ansamblu (binar) este un vector
ce poate fi vazut ca un arbore binar aproape complet (1). Fiecare
cheie din arbore corespunde unui element din vector. Arborele este
complet pe toate nivelele cu exceptia celui mai de jos, unde exista
chei incepand din stanga pana la un anumit punct.
Un vector A asociat unui ansamblu este caracterizat de 2 atribute:
- [Link] (numarul elementelor din vector);
- [Link]-size (numarul de elemente din heap) ( chiar daca
A[1 [Link]] contine numere, doar elementele din
A[1 [Link] size], unde 0 [Link] size [Link]), sunt
elemente valide in heap.
Figure : Un max-ansamblu vazut ca (a) arbore binar si (b) vector. In
interiorul cercurilor sunt valorile fiecarui nod. Numarul de deasupra este
indicele corespunzator in vector. Deasupra si sub vector sunt trasate
liniile aratand relatiile tata-fiu. Parintii sunt intotdeauna la stanga
descendentilor. Inaltimea arborelui este 3; nodul cu indicele 4 (avand
valoarea 8) are inaltimea 1.
Figure : Un max-ansamblu vazut ca (a) arbore binar si (b) vector.
root = A[1];
Pentru indice i al unui nod, se poate calcula usor indicii
parintelui sau si al descendentilor sai stang si drept:
void PARENT(int i) {return i/2;}
void LEFT(int i) {return 2*i;}
void RIGHT(int i) {return 2*i+1;}
Sunt 2 tipuri de arbori binari partiali:
- max - heap (max-ordonat)
( nod i 6= root A[PARENT(i)] A[i])
Maximul elementelor se afla in root
- min - heap (min-ordonat)
( nod i 6= root A[PARENT(i)] A[i])
(Minimul elementelor se afla in root)
Pentru algoritmul HeapSort va fi folosita o structura de tip arbore
partial max-ordonat.
Se defineste inaltimea unui nod intr-un heap, drept numarul de
muchii al celei mai lungi cai directe de la nod la o frunza.
Inaltimea unui ansamblu este inaltimea radacinii sale.
Cum un ansamblu cu n elemente se bazeaza pe un arbore binar
complet, inaltimea lui este (lg n). Se poate demonstra ca
operatiile de baza pe un ansamblu ruleaza in timp cel mult
proportional cu inaltimea arborelui, deci O(lg n).
Proceduri de baza folosite intr-un algoritm de sortare si o structura
de date de tip coada cu prioritati:
MAX-HEAPIFY: - timp O(lg n) - pastreaza proprietatea de
arbore max-ordonat;
BUILD-MAX-HEAP: - timp O(n) - creaza un arbore
max-ordonat pornind de la un vector nesortat;
HEAPSORT: - timp O(n lg n) - sorteaza un vector;
Pastrarea proprietatii de arbore partial max-ordonat
Procedura MAX-HEAPIFY primeste ca parametri un vector si un
indice al unui element din vector. Se presupune ca arborii binari cu
radacinile LEFT (i), respectiv RIGHT (i) sunt arbori partial
max-ordonati, dar e posibil ca A[i] sa fie mai mic decat
descendentii sai, astfel incalcand conditia de arbore max-ordonat.
Procedura MAX-HEAPIFY
void MAX-HEAPIFY (int A[], int i)
{ int l = LEFT(i);
int r = RIGHT(i);
if ((l <= [Link]-size) && (A[l] > A[i]))
largest = l;
else
largest = i;
if ((r <= [Link]-size) && (A[r] > A[largest]))
largest = r;
if (largest != i)
// interschimba(A[i],A[largest]);
MAX-HEAPIFY (A, largest)
}
Procedura MAX-HEAPIFY
La fiecare pas se determina maximul dintre A[i], A[LEFT(i)] si
A[RIGHT(i)]. Variabila largest stocheaza indicele elementului
maxim.
Daca maximul este A[i] atunci subarborele cu radacina in nodul i
este deja max-ordonat si procedura se termina.
Altfel, daca unul din cei doi descendenti contine maximul, A[i] se
interschimba cu A[largest], nodul i si descendentii sai satisfacand
conditia de arbore partial max-ordonat.
Totusi subarborele avand drept radacina nodul indexat de variabila
largest, poate viola conditia de max-ordonare, in consecinta,
procedura MAX-HEAPIFY apelandu-se recursiv pe acest
sub-arbore.
Figura 3 exemplifica apelul procedurii MAX-HEAPIFY.
Procedura MAX-HEAPIFY
Figure : Apelul MAX-HEAPIFY(A,2), unde [Link]-size = 10.
(a) Configuratia initiala A[2] violeaza conditia de arbore max-ordonat;
(b) Interschimbare(A[2],A[4]): A[2] respecta conditia, dar A[4] nu, deci
se apeleaza recursiv MAX-HEAPIFY(A,4); (c) Interschimbare(A[4],A[9])
si apel recursiv MAX-HEAPIFY (A,9) - nu se mai fac alte schimbari.
Analiza costurilor
Timpul de executie a procedurii MAX-HEAPIFY pe un sub-arbore
de inaltime n cu radacina intr-un nod i este dat de:
I
(1): costul stabilirii unei relatii intre A[i], A[LEFT (i)] si
A[RIGHT (i)];
Timpul de rulare a procedurii pe un sub-arbore cu radacina
intr-un descendent al nodului i (presupunand ca apelul
recursiv are loc).
Sub-arborii descendenti au inaltimea cel mult 2n/3 (cazul cel mai
defavorabil avand ultimul nivel pe jumatate plin), deci putem da
urmatoarea relatie de recurenta:
T (n) T (2n/3) + (1).
Solutia acestei recurente, obtinuta prin cazul 2 al Teoremei Master,
este T (n) = O(lg n). Alternativ, se poate spune ca timpul de
executie a procedurii MAX-HEAPIFY pe un nod de inaltime h este
de ordinul O(h). Figura 3 prezinta un exemplu de apel al acestei
proceduri.
Construirea unui ansamblu
Se foloseste procedura MAX-HEAPIFY de jos in sus pentru a
transforma un vector de lungime n intr-un ansamblu.
Elementele A[(bn/2c+1) n] sunt frunze, deci se incepe cu un
Ansamblu de lungime 1.
BUILD-MAX-HEAP parcurge nodurile ramase in ordine inversa, de
la n/2 la 1, si apeleaza MAX-HEAPIFY
void BUILD-MAX-HEAP (int A[])
{ [Link]-size = [Link];
for (i = [Link]/2; i >= 1; i--)
MAX-HEAPIFY(A,i)
}
Figura 4 prezinta un exemplu de apel al acestei proceduri.
Construirea unui ansamblu
Figure : Exemplu de apel BUILD-MAX-HEAP(A), cu [Link]-size = 10.
Construirea unui ansamblu
Costul fiecarui apel MAX-HEAPIFY este O(lg n), iar
BUILD-MAX-HEAP face O(n) asemenea apeluri.
Concluzia, complexitatea este O(n lg n).
Algoritmul HeapSort
Algoritmul HeapSort incepe prin apelarea procedurii
BUILD-MAX-HEAP pentru a construi un max-ansamblu.
Elementul maxim este stocat in radacina A[1]. La fiecare operatie
conditia indeplinita este ca mutarile sa nu afecteze proprietatea de
arbore partial max-ordonat.
void HEAPSORT(int A[])
{
BUILD-MAX-HEAP(A);
for (i = [Link]; i >= 2; i--)
interschimba(A[1],A[i])
[Link]-size --;
MAX-HEAPIFY(A,1)
}
Figura 5 prezinta un exemplu de sortare, dupa ce initial a fost
construit max-ansamblul.
Sortarea cu Ansamble
Figure : (a) Ansamblul max-ordonat obtinut prin BUILD-MAX-HEAP;
(b)-(j) Ansamblul dupa fiecare apel al MAX-HEAPIFY: doar nodurile cu
gri deschis raman; (k) vectorul sortat rezultat
Procedura HEAPSORT are complexitatea de O(n lg n) deoarece
apelul procedurii BUILD-MAXHEAP are O(n) si fiecare din cele
n-1 apeluri ale procedurii MAX-HEAPIFY se face in timp O(lg n).