You are on page 1of 11

o Definitia arborelui Huffman o Proprietăţi ale arborelui Huffman o Creare arborelui Huffman o Aplicaţia 1: Codul Huffman o Aplicaţia 2: Unirea fişierelor sortate o Aplicaţia 3: Generarea numerelor aleatoare

Definiţie:

Un arbore Huffman este un arbore binar care minimizează suma f (i)D (i) , unde i reprezintă un nod frunză, f(i) este frecvenţa sau ponderea frunzei i, iar D(i) este lungimea drumului de la rădăcină la frunza i. În fiecare aplicaţie, f(i) are un sens fizic diferit.

i

Proprietăţi:

Arborele Huffman are următoarele proprietăţi:

  • - fiecare nod intern are doi descendenţi;

  • - nodurile cu frecvenţe mai mici se află mai departe de rădăcină;

  • - cele mai mici două frecvenţe sunt aşezate pe poziţiile cele mai depărtate de rădăcină

Exemplu:

Fie un alfabet

care conţine literele

a’,

b’,

c’,

d

şi

e’, ceea

ce

reprezintă numele frunzelor ilustrate in tabelul urmator cu frecvenţele lor corespunzătoare.

Caracterul Frecvenţa a 20 b 11 c 8 d 12 e 49
Caracterul
Frecvenţa
a
20
b
11
c
8
d
12
e
49

Conform tabelului frunzele ‘c’ şi ‘b’ vor fi asezate cel mai departe faţă de rădăcină. Cele două frunze cu frecvenţa cea mai mică trebuie

aşezate astfel încât să păstrăm suma

f (i)D (i) la valoarea ei minimă.

i

În cazul în care nu s-ar face această aşezare, suma nu ar fi minimă. Acest lucru ar contrazice definiţia arborelui Huffman. În acest caz, ar trebui să schimbăm frunza cu o frecvenţă mai mică aşezând-o mai departe de radăcină. De asemena putem demonstra că fiecare nod intern trebuie să aibă doi descendenti pentru a fi un arbore Huffman.Să considerăm cazul în care ştergem frunza ‘a’ din arborele de mai jos.

100 0 1 51 e 49 0 1 31 a 20 0 1 19 d 12
100
0
1
51
e
49
0
1
31
a
20
0
1
19
d
12
0
1
c
b
8
11

Ştergând frunza ar rezulta un arbore în care suma i f (i) D (i) nu ar fi minimă. Aşadar, trebuie să reconstruim arborele, ştergând o frunză din subarborele nodului, pentru a face acest nod al doilea fiu. Arborele rezultat este cel de mai jos:

80 0 1 31 e d 2
80
0
1
31
e
d
2

0

1

49

 

19

12

0

1

 

8

11

După ce au fost identificate două frunze cu frecvenţele cele mai mici, se poate realiza ştergerea sau înlocuirea lor cu un nod intern. În aşa fel, problema este redusă ca dimensiuni.

Arborii Huffman nu sunt unici. Adică, poţi avea arbori diferiţi, pentru acelaşi set de frunze cu aceleaşi frecvenţe. De exemplu,dacă ai frunze cu aceeaşi frecvenţă, poziţia unora fată de celelalte nu este importantă.

3

Construirea arborelui Huffman

S-a realizat un algoritm cu o eficienţă O(n log n) pentru construirea unui arbore Huffman, datorită lui Hu şi a lui Tucker. Se foloseşte un vector de noduri ce conţin o frecvenţă şi pointeri către dreapta şi stânga.

Număr

 

1

2

.

.

.

.

Frunze

.

.

.

.

 

.

.

.

.

.

N

n+1

Noduri interne

n+2

.

.

.

 

.

Rădăcina

2n-1

f(i)

Stânga

Dreapta

f 1

0 0 0
0
0
0

0

f 2

0

f 3

0

.

.

.

.

.

.

.

.

.

.

.

G

.

.

I

.

.

V

.

.

E

.

.

N

.

.

.

.

.

.

.

.

.

.

.

.

.

.

0

0

f n

0

0

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

În jumătatea de sus a tabelei, numerotată de la 1 la n, avem frunzele unui arbore Huffman. Acestea au anumite frecvene date, şi nu au successor stâng sau drept, De aceea se pune “0” pe coloanele respective. În partea de jos a tabelei, între n+1 şi 2n-1, avem nodurile interne,incluzând rădăcina, de pe poziţia 2n-1.Frecvenţele lor pot fi calculate de succesorii lor stâng, respectiv drept. După cum vom vedea mai departe, cel mai slab caz este de complexitate O(n log n). Alfabetul este aranjat într-un heap, care are, prin definiţie, cele mai mici elemente mai sus. Cheile după care este ordonat heap-ul sunt frecvenţele caracterelor. Heap-ul este iniţial format din n perechi (i, f(i))

4

corespunzătoare frunzelor. La fiecare iteraţie, două elemente de frecvenţe minime sunt şterse şi este creat un nod intern.Frecvenţa acestui nod intern nou format este suma frecvenţelor succesorilor săi, şi este reprezentat printr-un nou “supercaracter”. Acest nod este inserat în heap şi procesul se repetă.

Algoritmul Hu – Tucker

O(n)

O(n log n)

Se foloseşte heap-ul ce contine perechile (1,f(1)), ,(n,f(n)) .. FOR i = n+1 TO 2n-1 DO (l,f l ) <--- Deletemin(Heap) (r,f r ) <--- Deletemin(Heap) f i <--- f l + f r Insert ((i,f i ), Heap) Left[i] <--- l Right[i] <--- r RETURN

Instrucţiunea “for” care este executată de n-1 ori pentru un alfabet de n litere extrage în mod repetat cele două noduri cu cele mai mici frecvenţe şi le înlocuieşte cu un alt nod, având frecvenţa suma frecventelor celorlalte două noduri. Acest nou nod are drept descendenţi nodurile anterioare cu frecvenţele cele mai mici. Cel mai slab caz are complexitatea O(n log n).

5

Aplicaţia 1: Codul Huffman

Un limbaj este format din simboluri sau caractere. Setul de simboluri al unui limbaj se numeşte alfabet. Un cod de cuvinte este un mod de a reprezenta un simbol folosind alte simboluri. Fiecare simbol dintr-un alfabet are propriul său cod. Colecţia de coduri de cuvinte formează un cod. Codurile sunt folosite în multe aplicaţii pe calculator. O astfel de aplicaţie este comprimarea şi decomprimarea datelor. O altă aplicaţie des întâlnită este folosită în transmiterea datelor. Datele sunt transmise prin fire de telefon sau cabluri de date ca semnale electrice.De când aceste semnale electrice sunt o formă a limbajului binari, datele trebuie codificate. Pentru a face transmiterea cât mai rapidă, ne-am dori un cod eficient cu cea mai mică lungime medie a cuvintelor din cod. Oricum aceasta lungime medie nu este pur şi simplu media lungimilor tuturor cuvintelor, ci mai degrabă media lungimii fiecarui cuvânt, înmulţită cu probabilitatea de apariţie a simbolului P(i), aşa cum indică şi formula următoare:

Aplicaţia 1: Codul Huffman Un limbaj este format din simboluri sau caractere. Setul de simboluri al

unde

P i

este

probabilitatea simbolului. Probabilitatea unui simbol

reprezintă probabilitatea ca acel simbol să apară în text.Ca întotdeauna, suma probabilităţilor P(i) este 1. Dacă luăm primul nostru exemplu, cel cu cinci litere ale alfabetului, ilustrat în Tabela 1, putem genera arborele Huffman pentru el. Frecvenţa se poate da sub formă de probabilităţi, procentaj sau sub orice alta formă numerică. 100

0 1 51 e 49 0 1 31 a 20 0 1 19 d 12 0
0
1
51
e
49
0
1
31
a
20
0
1
19
d
12
0
1
c
b
8
11

6

Caracter Frecvenţa Cod A 20 10 B 11 1111 C 8 1110 D 12 110 E
Caracter
Frecvenţa
Cod
A
20
10
B
11
1111
C
8
1110
D
12
110
E
49
0

Codul prefixelor poate fi vizualizat printr-un arbore,având frunzele corespunzătoare simbolurilor. Codul pentru fiecare caracter al alfabetului este generat, urmărind drumul de la rădăcină spre caracter, unde fiecare ramură stângă este notată cu 0, iar fiecare ramură dreaptă cu 1. Dacă probabilităţile sunt exacte, atunci codul Huffman dă cea mai bună medie dintre numarul de biţi şi simboluri. Aceasta este o metodă de optimizare a arborilor, folosind arbore Huffman, unde frecvenţa f(i) este înlocuită de probabilitatea P(i). Folosind exemplul nostru putem calcula lungimea medie a cuvintelor din cod:

0.49*1 + 0.20*2 + 0.12*3 + 0.11*3 + 0.08*3 = 1.82

7

Aplicaţia 2: Concatenarea fişierelor sortate

Vrem să concatenăm n fişiere sortate de lungimi s(1),…, s(n) într- un fişier mai mare, făcând un număr minim de comparaţii. Numărul de comparaţii necesar pentru a concatena două fişiere sortate de lungimi m, respective n este, în cel mai rău caz, m+n (de fapt sunt m+n-1 comparaţii, dar vom ignora “-1” pentru moment). Putem uni doar câte două fişiere o dată, de aceea ordinea în care se unesc este importantă. De exemplu, avem cinci fişiere de lungimi 200, 150, 810, 300 şi 40.Să încercăm să le unim în această ordine.Mai întâi unim fişierele de lungimi 200 şi 150 şi se obţine un fişier de lungime 350. Apoi unim fişierul de lungime 350 cu cel de lungime 810, rezultând un fişier de lungime 1160.Apoi acesta de 1160, cu cel de 300 şi obţinem un fişier cu o lungime de 1460. Şi în sfârşit, unim fişierele de lungimi 1460 şi 40, obţinând un fişier de lungime 1500. Acest proces se poate vizualiza prin arborele binar de mai jos.

Aplicaţia 2: Concatenarea fişierelor sortate Vrem să concatenăm n fişiere sortate de lungimi s (1),…, s

Fiecare fişier este o frunză a arborelui. Două noduri cu frecvenţele cele mai mici se unesc formând un fişier părinte mai mare. Acest mecanism pare bun, dar este de fapt o pierdere de timp. Pentru că fisierele anterioare sunt unite iar şi iar, ca părţi din fişierul mai mare, numărul de comparaţii necesar pentru a uni fişierele în această ordine este

200+150+350+810+1160+300+1460+40=4470

Există un mod mult mai eficient de a proceda, ce va necesita mai puţine comparaţii. Dacă am privi din perspectiva arborelui, numărul total de comparaţii este suma dupa fiecare frunză i din produsul dintre lungimea fisierului s(i) înmulţită cu distanta de la rădăcină D(i).

8

Numărul de comparaţii =

s(i) * D(i)

i

Din nou, avem aceeaşi optimizare: vrem să minimizăm suma

i

s(i)D (i) . Acum s(i)

joacă rolul lui

f(i).

Metoda

optimă

de

a

uni

fişierele ar fi să facă acest lucru în ordinea crescătoare a lungimilor: se uneşte fişerul de lungime 40 cu cel de lungime 150, rezultând unul de

lungime 190, se uneşte fişierul de 190 cu cel de lungime 200, şi rezultă unul de lungime 390, se uneşte fişierul de lungime 390 cu cel de 300, rezultă un fişier de lungime 690, apoi se uneşte cel de lungime 690 cu cel de lungime 810 şi rezultă unul de lungime 1500. Acest procedeu dă un

număr

total

de

comparaţii

 

de:

40+150+190+200+390+300+690+810=2770

(în

comparaţie

cu

4470

obţinute anterior). Astfel, cele mai mici fişiere sunt cele mai des unite.

Este analog cu problema caracterelor cu frecvenţa cea mai mică.

150 0 69 81 0 0 30 39 0 0 19 20 0 0 4 15
150
0
69
81
0
0
30
39
0
0
19
20
0
0
4
15
0
0

Dintre toti, arborele Huffman este optim. Una din proprietaţile de bază ale arborelui Huffman este aceea că cele mai mici frecvente se află cel mai departe de rădăcină iar acestea se unesc într-un nod părinte. Reţinând acest lucru, nu avem neapărată nevoie de arbore. Singurul lucru pe care trebuie să-l reţinem este că cele mai mici două fişiere vor fi unite mai întâi. Acest pas se va repeta .

9

Aplicaţia 3: Generarea numerelor aleatoare

Problemă: Să se genereze aleator un număr întreg dându-se probabilitatea de apariţie. Metoda folosită pentru rezolvare se bazează pe un arbore binar în care fiecare frunză corespunde unui număr întreg. Se ia un număr oarecare U din intervalul [0,1] şi se parcurge arborele dinspre rădăcină, aşa încât fiecare frunză este parcursă cu probabilitatea corectă. Probabilitaţile din exemplul nostru sunt cele ilustrate în figura de mai jos. De exemplu probabilitatea de apariţie a cifrei “1” este 0.15, pe când probabilitatea de apariţie a lui “2” este 0.20.Vrem să construim un arbore care va parcurge fiecare din cele şase frunze cu probabilitatea corectă.

Aplicaţia 3: Generarea numerelor aleatoare Problemă: Să se genereze aleator un număr întreg dându-se probabilitatea de

Algoritmul pentru parcurgerea arborelui asociază fiecărui nod i o valoare prag t(i), care este suma valorilor frunzelor din stânga acestuia. Pentru a găsi valoarea t(i) se parcurge arborele în preordine. Preord (i) Dacă i ≠ NULL atunci t(i) = t(i) + P(i), unde P(i) este frecvenţa unei frunze sau 0 pentru un nod intern

Preord (st [i]) Preord(dr [i])

10

Dacă acest lucru este stabilit, fiecare nod intern are o valoare ce ne permite să parcurgem mai departe arborele, parcurgând frunzele cu probabilitatea corectă. Arborele de mai jos ilustrează valorile pentru fiecare nod intern. Vom compara aceste valori cu numărul aleator dat.

Dacă acest lucru este stabilit, fiecare nod intern are o valoare ce ne permite să parcurgem

Fiecare dintre aceste şase probabilităţi apar într-o gamă între 0 şi 1. Lungimea acestui sir de numere este direct proporţional cu frecvenţa lor. Deci, dacă numărul aleator dat este între 0 şi 0.10, vom ajunge la frunza “3”.În acelaşi fel pentru a parcurge frunza “6” trebuie ca numărul aleator să fie între 0.72 şi 0.85. Lungimea şirului cu ajutorul căruia este atinsă frunza ”6” este 0.13, care este şi probabilitatea ei de apariţie.

1 comparaţie = 1 unitate de timp

Deci, conform celor de mai sus vom avea nevoie de 3 unitaţi de timp pentru a atinge frunza “6” şi de 2 unităţi de timp pentru frunza “2”.

Timpul total necesar este i

p(i) * D(i) , unde i sunt frunzele, iar

p(i)probabilităţile date. Arborele care optimizeaza timpul de execuţie este arborele Huffman. Deci trebuie să-l construim ca mai sus.

11