Sunteți pe pagina 1din 11

Algoritmi fundamentali - Curs 4

Conf. dr. Aurelian Nicola


2 martie 2018

1 Heap-uri binare

2 Introducere
Un heap (engl. grămada conform [2]) este un vector care poate fi privit ca
un arbore binar, aşa cum se vede in figura 1 de mai jos Adiacent fiecărui nod

Figura 1: Structura unui heap.

din arbore se află câte un număr, reprezentând poziţia ı̂n vector pe care ar
avea-o nodul respectiv. Pentru cazul considerat, vectorul echivalent ar fi
(12, 10, 11, 10, 7, 9, 3, 2, 8, 1, 4, 3).

1
Se observă că nodurile sunt parcurse de la stânga la dreapta şi de sus in jos.
O proprietate necesară pentru ca un arbore binar să se poată numi heap este
ca toate nivelurile să fie complete, cu excepţia ultimului, care se completează
ı̂ncepând de la stânga şi continuând până la un anume punct. De aici se
deduce uşor că ı̂nălţimea unui heap cu N noduri este

h = log2 (N ).

Reciproc, numărul de noduri ale unui heap de inaltime h este

h ∈ [2N , 2N +1 − 1].

Structura de heap permite efectuarea multor operatii intr-un timp foarte


bun:

• Cautarea maximului ı̂n O(1);

• Crearea unei structuri de heap dintr-un vector oarecare ı̂n O(N );

• Eliminarea unui element ı̂n O(log N )

• Inserarea unui element ı̂n O(log N)

• Sortarea elementelor din heap in O(N log N)

3 Arbori binari
O structură de date heap binar este un arbore binar care este complet
umplut pe toate nivelurile, poate cu excepţia cea mai mică, care va fi um-
plut de pe partea stângă până la un punct. Datorită acestor caracteristici,
este us̆or de a reprezenta arborele ı̂ntr-un array. Figura 2 prezintă struc-
tura logică (top) heap şi, de asemenea, modul ı̂n care pot fi stocate ı̂ntr-un
array(bottom). Observaţi cum fiecare strat al arborelui ocupă locuri con-
secutive ı̂n array. Rădăcina arborelui este A[1], şi având ı̂n vedere indicele
i al unui nod, indicii părinte Parent(i), fiu stânga Left(i) şi fiu dreapta
Right(i) pot fi calculaţi foarte simplu. Secvenţele de pseudocod care descriu
acest calcul sunt prezentate mai jos.

2
Parent(i)
1 return bi/2c

Left(i)
1 return 2i

Right(i)
1 return 2i + 1
Heap binar poate fi un heap ı̂n care căutăm valoarea maximă sau valoarea
minimă. Ca un heap maxim, fiecare nod indexat de i, altele decât rădăcina
(de exemplu: i 6= 1), are
A[Parent(i)] ≥ A[i].
În schimb ı̂ntr-un heap minim, fiecare nod indexat de i, altele decât rădăcina,
are următoare proprietate
A[Parent(i)] ≤ A[i].
În ce priveşte restul capitolului despre heap-uri vom considera un heap de
tip maxim. Această proprietate face diferenţa ı̂ntre un heap binar şi arbore
binar de căutare. Într-un arbore binar,
left child ≤ parent < right child.
Cu toate acestea, ı̂ntr-un heap maxim, parent ≥ left child şi parent ≥
right child. În concluzie, un arbore binar de căutare poate fi privit ca fiind
sortat, ı̂n timp ce un heap nu se poate privi ca fiind sortat.

4 Mentinerea proprietatii de heap


Presupunând că avem deja un heap maxim, operaţiuni pe un heap maxim,
de exemplu introducerea sau ştergerea, poate provoca heap-ul să–şi piardă
proprietatea heap maxim. Rutina Max-Heapify poate fi folosită pentru
a rectifica acest lucru. Avem nevoie de un vector A şi indicele i pentru
a indexa valorile din acest vector. Mai mult presupunem că A este deja
un heap maxim. Atunci procedura de refacere a proprietăţii de heap este
următoarea:

3
Figura 2: Structura unui heap maxim. Această figură ilustrează structura
heap-ului din punct de vedere logic. În partea de jos a figurii observăm
valorile corespondente aşezate ı̂n vector.

4
Max-Heapify(A, i)
1 l ← Left(i)
2 r ← Right(i)
3 if l ≤ heap-size[A] and A[l] > A[i]
4 then largest ← l
5 else largest ← i
6 if r ≤ heap-size[A] and A[r] > A[largest]
7 then largest ← r
8 if largest 6= i
9 then Swap A[i] and A[largest]
10 Max-Heapify(A, largest)

5 Construirea unui heap


Rutina Build-Max-Heap ia orice vector A, şi lucrează succesiv din partea
de jos a arborelui urmând să ajungă ı̂n partea de sus, foloseşte Max-Heapify
pentru a construi proprietatea de heap.

Build-Max-Heap(A)
1 heap-size[A] ← length[A]
2 for i ← blength[A]/2c downto 1
3 do Max-Heapify(A, i)

(a) Arborele iniţial. Build-Max-Heap lucrează succesiv din partea de


jos. 18 este mai mare decât copii săi, astfel ı̂ncât nu se face nimic. (b) Max-
Heapify este numit pe 3, şi aşa este schimbat cu 12. (c) 1 va fi schimbat cu
8. (d) 2 va fi trimis la partea de jos a arborelui, ı̂n primul rând schimbat cu
18, apoi cu 4. (e) CândMax-Heapify este numit pe 5, acesta este trimis la
partea de jos a arborelui. (f) Rezultat heap maxim. Observăm că această
rutină se execută ı̂n mod recursiv. Complexitatea execuţiei acestei rutine
este dată de adâncimea arborelui.

5
Figura 3: În (a), 5 a fost adăugat la poziţia 2 ı̂ntr-un heap maxim. Prima
iteraţie a Max-Heapify swap-uri (schimbă) 5 cu 14, la litera (b), iar apoi
swap-uri (schimbă) 5 cu 12 la litera (c).

6
Figura 4: a

7
6 Cozi cu prioritate
O coadă cu prioritate este o structură de date pentru menţinerea unui set
S de elemente, fiecare cu o valoare asociată numit cheie (key). Cozile cu
prioritare sunt adesea folosite pentru a extrage un element cu o proprietate
deosebita dintr-o mulţime dinamică. O coadă cu prioritate de tip maxim
suportă următoarele operaţiuni.

• Insert (S, x) introduce elementul x ı̂n set S., de exemplu, S ← S ∪ {x}.

• Maximum(S) ı̂ntoarce elementul S cu cea mai mare cheia.

• Extract-Max(S) elimină şi returnează elementul S cu cea mai mare


cheie.

• Increase-Key(S, x, k) creşte valoarea cheie elementului x la noua valoare


k, care se presupune a fi cel puţin la fel de mare ca valoare cheie curente
a lui x.

Un heap maxim poate fi folosit ca o max-coada cu prioritate (coadă de


max prioritate), ca ı̂ntotdeauna se susţine că primul element este maximul.
Folosind Max-Heapify, se poate asigura cu uşurinţă că anumite modificări,
de exemplu ı̂ndepărtarea elementului maxim, va menţine primul element ca
fiind maxim.

8
Heap-Maximum(A)
1 return A[1]

Heap-Extract-Max(A)
1 if heap-size[A] < 1
2 then error “Heap underflow”
3 max ← A[1]
4 A[1] ← A[heap-size[A]]
5 heap-size[A] ← heap-size[A] − 1
6 Max-Heapify(A, 1)
7 return max

Heap-Sift-Up(A, i)
1 while i > 1 and A[Parent(i)] < A[i]
2 do Swap A[i] with A[Parent(i)]
3 i ← Parent(i)

Heap-Increase-Key(A, i, k)
1 if k < A[i]
2 then error “New key is smaller than current key”
3 A[i] ← k
4 Heap-Sift-Up(A, i)

Max-Heap-Insert(A, k)
1 heap-size[A] ← heap-size[A] + 1
2 A[heap-size[A]] ← k
3 Heap-Sift-Up(A, heap-size[A])

Heap-Increase-Key (a) Heap-ul maxim original, cu cheia să fie cres-


cută umbrită ı̂n galben. (b) Cheia este crescut la 17. (c) 17 este schimbat cu
părintele. (d) Proprietatea heap-ului maxim este restaurat, schimbând 17 cu
părintele din nou.

9
10

Figura 5: b
Bibliografie
[1] Peter Braess, Advanced Data Structures, 2008.

[2] http://www.infoarena.ro/

[3] http://cs.anu.edu.au/ Alistair.Rendell/Teaching/

[4] ADVANCED DATA STRUCTURE and Algorithms for industry, Silicon


Institute of Technology.

[5] Thomas Cormen, Charles Lerseison, Ronald Rivest, Clifford Stein, In-
troduction to algorithms, Third edition, MIT Press 2009.

11

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