Sunteți pe pagina 1din 10

Transmisiunea digitală a informaţiei. Compresie fără pierderi. Aplicaţii şi lucrări practice.

Algoritmi statistici adaptivi de tip Huffman

1. Obiectivul lucrării

Scopul acestei lucrări este prezentarea modului de implementare a algoritmilor


Huffman adaptivi FGK şi Vitter.

2. Introducere teoretică

Termenul de compresie a datelor a apărut în contextul în care se manifesta o


necesitate evidentă de a atinge rate mari de transfer în reţele sau de a stoca o cantitate
cât mai mare de informaţii folosind cât mai puţin spaţiu. Compresia datelor este
necesară în zilele noastre şi este foarte des folosită, mai ales în domeniul aplicaţiilor
multimedia.
Codurile Huffman rezolvă problema găsirii unui tabel optim al cuvintelor de cod
pentru simboluri cu distribuţie arbitrară a probabilităţii. În această lucrare, se vor
folosi următoarele convenţii. Şirul de caractere necomprimate va fi mesajul şi
alfabetul său va fi alfabetul original sau alfabetul mesajului. Ieşirea comprimată va fi
alcătuită din simbolurile rezultate. Se va numi (cuvânt de cod) un şir de simboluri
rezultate, asociate unui simbol din mesaj, iar tabelul cuvintelor de cod va fi setul
codurilor asociate tuturor simbolurilor din alfabetul mesajului. Un tabel al cuvintelor
de cod poate fi văzut ca o funcţie F care asociază simbolurile din mulţimea A,
alfabetul mesajului, cu cele din submulţimea B, a tuturor şirurilor (care au elemente)
unic determinate, formate din alfabetul rezultat B.
Huffman, în lucrarea sa de referinţă din 1952, prezintă procedura de construire a
codurilor optimale de lungime variabilă, dându-se o distribuţie cu frecvenţă arbitrară
pentru un alfabet finit. Această procedură este construită pe baza câtorva condiţii care,
dacă sunt satisfăcute, produc un tabel optimal al cuvintelor de cod.

Primele condiţii sunt după cum urmează:


a) nici un cod de cod nu este prefixul altui cuvânt de cod;
b) nu este necesară nici o informaţie suplimentară ca delimitator între coduri.
Aceste două cerinţe conduc la formularea următoarelor trei:
c) L(a1)  L(a2)  ...  L(an), unde L(an) este lungimea cuvântului de cod an.
d) două cuvinte de cod au lungimea Lmax şi sunt identice, în afara ultimului bit.
e) Fiecare cuvânt de cod posibil de lungime Lmax–1 ori este deja folosit, ori are
unul din prefixele sale folosit drept cuvânt de cod.

Un arbore Huffman este un arbore binar cu noduri ponderate care are


proprietatea de fraternitate, iar ponderea unui nod părinte este egală cu suma
ponderilor urmaşilor săi direcţi. Fiecare nod al arborelui Huffman este caracterizat de
3 parametri: ponderea asociată, poziţia sa în cadrul arborelui şi tipul său. În cazul
codării Huffman, este necesar să se creeze mai întâi un dicţionar. Acest dicţionar
conţine caracterele distincte aflate în textul dat, fiecărui caracter asociindu-i-se o
pondere (calculată ca raportul dintre numărul de apariţii al acelui caracter în mesaj şi
lungimea mesajului), iar ulterior, în urma executării algoritmului, cuvintele de cod
formate pentru fiecare caracter. Caracterele distincte se ordonează în ordinea
descrescătoare a ponderilor.

14
Transmisiunea digitală a informaţiei. Compresie fără pierderi. Aplicaţii şi lucrări practice.

Formarea arborelui de construcţie a codului Huffman binar decurge după


următorii paşi:
Pasul 1. Sunt localizate cele două noduri libere cu cea mai mică pondere.
Pasul 2. Pentru nodurile găsite la pasul 1 se creează un nod părinte. Acestui nod
nou creat i se va atribui o pondere egală cu suma ponderilor celor doi
urmaşi ai săi.
Pasul 3. Nodul părinte este adăugat listei de noduri libere a arborelui, iar cele
două noduri urmaş sunt eliminate din această listă.
Pasul 4. Unuia dintre nodurile urmaş îi este atribuită calea care este urmată în
cazul decodării unui bit de 0, iar celuilalt urmaş – calea care este
urmată în cazul decodării unui bit de 1.
Pasul 5. Paşii anteriori sunt repetaţi succesiv până în momentul în care mai
rămâne un singur nod liber. Acesta este desemnat ca fiind nodul
rădăcină al arborelui.

2.1. Algoritmul Faller, Galler şi Knuth (FGK)

Proprietatea de învecinare (Gallager, 1978); un arbore binar prezintă


proprietatea de învecinare dacă fiecare nod, cu excepţia nodului rădăcină, are un vecin
şi dacă nodurile pot fi ordonate în funcţie de pondere (în ordine descrescătoare), cu
fiecare nod adiacent în ordonare vecinului său din arbore. Un cod prefix binar este cod
Huffman dacă şi numai dacă arborele prezintă proprietatea de învecinare.

Algoritmul de codare FGK decurge după următorii paşi:


Pasul 1. La început, arborele este format dintr-un singur nod terminal, numit şi
nodul 0. Acesta este un nod special, folosit pentru a reprezenta cele n–
k mesaje neutilizate.
Pasul 2. La fiecare mesaj transmis, ambele părţi (codorul şi decodorul) trebuie
să incrementeze ponderile şi să refacă arborele de codare pentru a
menţine proprietatea de învecinare.
Pasul 3. La momentul de timp la care au fost deja transmise t mesaje, k dintre
ele fiind distincte (k < n), arborele obţinut este un arbore Huffman cu
k+1 noduri terminale, câte unul pentru fiecare mesaj, plus unul
corespunzător nodului 0. Dacă al (t+1)-lea mesaj este unul dintre cele k
mesaje deja transmise, algoritmul transmite codul curent (pentru
mesajul at+1), incrementează numărătorul corespunzător şi reface
arborele. Dacă apare un mesaj nefolosit, nodul 0 este divizat pentru a
crea o pereche de noduri terminale.
Pasul 4. Arborele este refăcut din nou. În acest caz, este transmis codul pentru
nodul 0; în plus, destinatarul trebuie să fie informat care dintre cele n–
k mesaje a apărut.

2.2. Algoritmul Vitter

Algoritmul Vitter este o variaţie a algoritmului FGK. Diferenţa principală între


algoritmul FGK şi algoritmul Vitter este modul în care sunt numerotate nodurile.
Algoritmul Vitter ordonează nodurile în acelaşi mod cu algoritmul FGK, dar cere ca
nodurile terminale cu o anumită pondere să preceadă nodurile interne cu aceeaşi
pondere şi adâncime, în timp ce în algoritmul FGK era suficient ca ponderile

15
Algoritmi statistici adaptivi de tip Huffman

nodurilor de la o anumită adâncime să fie aranjate de la stânga la dreapta, fără a face


distincţie între nodurile interne şi nodurile terminale. Această modificare este
suficientă pentru a garanta că algoritmul Vitter codează o secvenţă de lungime s cu nu
mai mult de s biţi faţă de algoritmul Huffman static, fără costul suplimentar de
transmitere către decodor a tabelei de probabilităţi sau a cuvintelor de cod.
Optimizările aduse de algoritmul Vitter pot fi sintetizate astfel:
 numărul de interschimbări prin care un nod este deplasat în sus în arbore la
refacere este limitat la 1;
 se minimizează valorile li (lungimea maximă a căilor) şi max{li} (înălţimea
arborelui).

3. Descrierea aplicaţiei

Programul are ca scop prezentarea modalităţilor de construcţie a arborilor pentru


codările Huffman, FGK şi Vitter. După cum se observă în figura 1, s-a creat o
fereastră principală în care poate fi introdus textul care urmează a fi codat şi se poate
alege tipul codării.

Fig. 1. Fereastra principală a programului.

Din cauza constrângerilor de construcţie a arborilor, s-au introdus limitări în


ceea ce priveşte textul care se doreşte a fi codat. Astfel, lungimea textului nu trebuie
să depăşească 50 de caractere, iar numărul caracterelor distincte să nu fie mai mare de
19. După introducerea textului, se alege tipul de codare dorit şi se deschide o nouă
fereastră pentru fiecare codare în parte.

3.1. Codarea Huffman

În figura 2 se poate observa modul de implementare a algoritmului Huffman. În


cadrul acestei ferestre, există patru butoane (ordonare, construire arbore, codare
Huffman, înapoi), un spaţiu de editare, trei coloane (caracter, pondere, cod) şi un
panou pentru desenare. În spaţiul de editare, apare textul introdus în cadrul ferestrei
principale, text care urmează a fi codat. Acest text nu poate fi modificat în cadrul
acestei ferestre. Acţionând primul buton (ordonare), se creează o matrice. În prima
coloană a matricei se introduc toate caracterele distincte, iar în a doua coloană se vor
introduce cuvintele de cod alocate. Practic, această matrice reprezintă dicţionarul, care
va putea fi folosit la decodare. Matricei i se asociază şi un vector în care se introduc
ponderile corespunzătoare fiecărui caracter din cadrul textului.

16
Transmisiunea digitală a informaţiei. Compresie fără pierderi. Aplicaţii şi lucrări practice.

Fig. 2. Fereastra pentru codarea Huffman.

Ponderea se calculează ca raportul dintre numărul de apariţii al caracterului


respectiv şi lungimea totală a textului. Suma ponderilor tuturor caracterelor trebuie să
fie egală cu 1.
nr _ ap(ai )
P(ai )  ,
L
unde P(ai) reprezintă ponderea caracterului ai, nr_ap(ai) reprezintă numărul de apariţii
a caracterului ai şi L reprezintă lungimea textului. Ponderile calculate trebuie să
îndeplinească condiţia:
k
 P (ai )  1 ,
i 1

unde k reprezintă numărul de caractere distincte ale textului dat.


După ce s-au calculat ponderile pentru toate caracterele distincte, atât caracterele
cât şi ponderile acestora se ordonează descrescător după valoarea ponderilor. În cadrul
ferestrei pentru codarea Huffman, apar primele două coloane, unde sunt afişate
caracterele distincte, respectiv ponderile acestora, după cum s-au ordonat, adică
descrescător.
La acţionarea celui de-al doilea buton (construire arbore), apare arborele
Huffman format cu caracterele din text, în cadrul panoului din dreapta, după cum se
observă în figura 2. Acest arbore se formează în felul următor:
 toate ponderile caracterelor se introduc într-o listă simplu înlănţuită, în
ordine crescătoare, lista având două câmpuri: valoarea (ponderea) şi nodul
corespunzător;

17
Algoritmi statistici adaptivi de tip Huffman

 se iau primele două elemente ale listei (adică, cele cu ponderile cele mai
mici), cu care se creează un arbore format din cele două noduri ca urmaşi şi
un părinte, cu valoarea (ponderea) egală cu suma ponderilor celor doi urmaşi
(în stânga se află nodul cu ponderea cea mai mică);
 primele două elemente ale listei cu care s-a format arborele sunt şterse din
listă şi se introduce un element nou, părintele format, locul său în listă fiind
în funcţie de valoarea sa, astfel încât lista să fie în permanenţă ordonată
crescător;
 se continuă algoritmul până când în listă nu mai există nici un element,
arborele fiind astfel creat.
Se apelează procedura de desenare a arborelui, acesta putând fi vizualizat în
cadrul panoului din dreapta. În cazul în care nu se încadrează în ecran, există bare de
defilare (scroll) în partea de jos şi în dreapta panoului, sau se poate mări panoul în
cadrul căruia se desenează, cu ajutorul butonului măreşte, aflat în stânga sus, în cadrul
panoului.
La acţionarea celui de-al treilea buton (codare Huffman) apare cea de-a treia
coloană în stânga panoului, în cadrul căreia se afişează cuvântul de cod obţinut pentru
fiecare caracter.
Fiecare nod care are urmaşi are în stânga o săgeată pe care este trecută valoarea
0, iar în dreapta valoarea 1. Cuvântul de cod pentru fiecare caracter se formează
citind, de la rădăcină până la nodul terminal asociat caracterului respectiv, valorile 0,
respectiv, 1, pe drumul cel mai scurt. Lungimea cuvântului de cod respectiv este egală
cu adâncimea la care se află nodul terminal. Adâncimea rădăcinii (primul nod părinte)
este 0 şi creşte cu o unitate pentru fiecare generaţie (fiecare rând de sus în jos). Toate
codurile astfel obţinute se trec pe a doua coloană a matricei care reprezintă
dicţionarul.
Cuvântul de cod va fi format înlocuind fiecare caracter din text cu codul obţinut
în urma algoritmului Huffman. Acest cuvânt de cod va fi transmis pe pagina
principală, unde se vor mai calcula lungimea codului, lungimea medie a codului,
entropia sursei şi eficienţa codării, după cum urmează:
 lungimea codului este numărul de biţi care formează cuvântul de cod;
 lungimea medie a codului este dată de formula:
k
Lm   P(ai ) L(ai ) [bit],
i 1

unde L(ai) este lungimea cuvântului de cod corespunzător caracterului ai;


 entropia sursei se calculează după formula:
k
H ( S )    P(ai )log2 P(ai ) [bit/simbol].
i 1

 eficienţa codării reprezintă raportul dintre entropia sursei şi lungimea medie


a codului (altfel spus, coloana 3 / coloana 2):
H (S )
E .
Li

Butonul înapoi şterge elementele create pentru a putea relua aplicaţia pentru un
alt text şi închide fereastra codării Huffman, întorcându-se la fereastra principală.

18
Transmisiunea digitală a informaţiei. Compresie fără pierderi. Aplicaţii şi lucrări practice.

Cele patru butoane trebuie acţionate în ordinea paşilor, pentru a realiza un


algoritm corect. În cazul în care un alt buton este acţionat înaintea celui precedent,
este afişat un mesaj care anunţă că butoanele trebuie apăsate în ordinea paşilor.

3.2. Codarea FGK

Algoritmul de codare FGK este dinamic. La citirea fiecărui caracter din textul
dat, se formează un arbore, care are toate proprietăţile arborelui Huffman.
La crearea unui astfel de arbore, se porneşte de la un nod cu valoarea (numărul)
0, iar primul caracter citit, împreună cu acest nod 0, creează primul părinte (rădăcină a
arborelui), după cum se observă în figura 3. De fiecare dată când apare un caracter
nou, acesta se înfrăţeşte cu nodul 0.

Fig. 3. Exemplu de formare a unui nod nou, înfrăţit cu nodul 0.

Fiecare nod al arborelui are următoarele câmpuri:


 caracter sau literă – în cazul nodurilor terminale, caracterul reprezintă
simbolul sau litera căreia îi corespunde nodul respectiv, iar nodurile interne
au caracterul vid;
 număr – reprezintă numărul de apariţii al acelui caracter în textul citit;
 codul sau cuvântul de cod se formează în urma formării arborelui în acelaşi
mod ca la algoritmul Huffman;
 adâncimea – reprezintă ordinul generaţiei de urmaşi la care s-a ajuns pornind
de la rădăcină (rădăcina având adâncimea 0);
 indexul – reprezintă numărul de ordine al nodurilor din arbore (citirea se
face de jos în sus şi de la stânga la dreapta, indexul 1 avându-l nodul cu
numărul 0, indexul 2 – ultimul nod introdus, indexul cel mai mare aparţinând
rădăcinii);
 adâncimea maximă – reprezintă numărul de generaţii următoare pentru
fiecare nod (un nod terminal are adâncimea maximă 0).
Modul de implementare al algoritmului FGK fiind dinamic, este necesară
implementarea acestui algoritm pe paşi.
În figura 4 se poate observa fereastra creată pentru codarea FGK. Aceasta
conţine două câmpuri de editare (prima conţine textul introdus în cadrul ferestrei
principale, iar cea de-a doua textul codat până în acel moment – reamintim că pentru
fiecare caracter citit se creează un nou arbore Huffman, iar acest lucru se evidenţiază
în cadrul aplicaţiei), două butoane, un tabel cu trei coloane şi un panou pentru
desenare.
Primul buton, intitulat Paşii algoritmului FGK, realizează practic întreg
algoritmul pentru fiecare caracter în parte, acest buton trebuind a fi acţionat pentru
fiecare caracter al textului.

19
Algoritmi statistici adaptivi de tip Huffman

Fig. 4. Fereastra pentru codarea FGK.

Dacă utilizatorul încearcă să se întoarcă în programul principal înainte de a fi


codat tot textul, apare mesajul “Nu aţi codat tot textul. Apăsaţi butonul de codare până
la terminarea şirului de caracter.”
Algoritmul se desfăşoară după următorii paşi:
 la acţionarea butonului se ia câte un caracter al textului în ordinea
introducerii de la tastatură;
 se verifică dacă acel caracter care urmează a fi introdus în arbore a mai
apărut anterior sau nu;
 dacă acest caracter a mai apărut, se incrementează valoarea (numărul)
nodului corespunzător caracterului respectiv şi se rearanjează arborele, care
trebuie să îndeplinească anumite condiţii (descrise în paragraful următor);
 dacă respectivul caracter nu a mai apărut anterior, se măreşte cu 2 valoarea
indexului fiecărui nod din arbore, se caută nodul cu numărul 0, valoarea sa
incrementându-se (numărul devine egal cu 1), şi se construiesc doi urmaşi
pentru acest nod găsit: cel din stânga devine nodul 0, iar cel din dreapta are
numărul 1 şi caracterul citit în acel moment din text (caracterul nodului 0
este tot caracterul vid, deşi este un nod terminal);
 caracterul nou apărut se introduce într-o matrice cu două câmpuri, primul
câmp reprezentând caracterul, iar cel de-al doilea cuvântul de cod format în
urma executării algoritmului;
 se rearanjează arborele, care se desenează în cadrul panoului din dreapta, şi
se afişează în stânga panoului un tabel cu toate caracterele distincte apărute
până în acel moment, numărul de apariţii al acestora şi cuvintele de cod
formate, după cum se observă în figura 4. Toate codurile se reactualizează
pentru fiecare caracter citit.

20
Transmisiunea digitală a informaţiei. Compresie fără pierderi. Aplicaţii şi lucrări practice.

Dacă este acţionat în continuare primul buton şi după codarea întregului text,
apare mesajul “Textul a fost codat în întregime”. Dacă se doreşte reluarea algoritmului
pentru un alt text sau chiar pentru acelaşi text, este necesară întoarcerea în fereastra
principală, ceea ce se poate realiza apăsând butonul înapoi.
Cel de-al doilea buton, înapoi, şterge elementele create pentru a putea relua
aplicaţia pentru un alt text şi închide fereastra codării curente, întorcându-se la
fereastra principală. Tot aici se transmit către fereastra principală (unde vor fi afişaţi)
parametrii codării, şi anume: cuvântul de cod format, lungimea codului, lungimea
medie a cuvintelor de cod, entropia sursei şi eficienţa codării.

Fig. 5. Afişarea parametrilor în cadrul ferestrei principale.

Condiţiile care trebuie îndeplinite la construcţia unui arbore FGK sunt


următoarele:
 nodurile trebuie să fie ordonate de jos în sus şi de la stânga la dreapta, în
ordinea crescătoare a valorii numerelor;
 nodul 0 trebuie să fie înfrăţit cu ultimul nod introdus, dacă valoarea acestuia
este cea mai mică, sau cu nodul având valoarea minimă;
 numărul de noduri terminale trebuie să fie egal cu numărul caracterelor
distincte, plus nodul 0;
 urmaşii aceluiaşi nod părinte sunt indexaţi consecutiv;
 ponderea fiecărui nod descreşte sau rămâne constantă odată cu creşterea
indexului asociat;
 dacă două noduri sunt pe acelaşi nivel ierarhic, urmaşii nodului de indice
mai mic au indici inferiori indicilor urmaşilor celuilalt nod.

3.3. Codarea Vitter

Modul de implementare a algoritmului pentru codarea Vitter este asemănător


celui de la algoritmul FGK. Există totuşi nişte diferenţe, în special în cazul condiţiilor
care trebuie îndeplinite la formarea arborelui. Condiţiile care apar în plus în acest caz
sunt următoarele:
 la introducerea unui caracter nou în arbore, acesta nu mai este urmaş al
nodului 0, ca la FGK, ci se caută nodul cu valoarea 1 având indexul cel mai
mare, acesta devenind părinte al nodului 0 şi al nodului nou introdus, iar
toate celelalte noduri mutându-se cu o poziţie, adică pe nodul cu indexul
având valoarea cu o unitate mai mică; pe poziţia nodului 0 apare un nod
terminal asociat unui anumit caracter (cel care fusese înfrăţit cu nodul 0.)

21
Algoritmi statistici adaptivi de tip Huffman

 chiar dacă un caracter citit este deja prezent în arbore, nodul asociat acestui
caracter îşi schimbă poziţia, luând locul nodului terminal cu aceeaşi valoare
şi cu indexul cel mai mare, toate celelalte noduri cu indexul mai mic decât
indexul nodului nou ocupat mutându-se pe nodul cu indexul cu o unitate mai
mică, până se ajunge la nodul modificat prin apariţia caracterului considerat;
 nodurile terminale preced nodurile interne;
 valorile indecşilor nodurilor sunt crescătoare de jos în sus şi de la stânga la
dreapta, faţă de cazul FGK, unde nu se respectă ordinea la fiecare nivel;
 adâncimea arborelui trebuie să fie minimă.

Fig. 6. Fereastra pentru codarea Vitter.

Fereastra pentru codarea Vitter, care poate fi observată în figura 6, are aceleaşi
componente şi este construită la fel ca fereastra pentru codarea FGK.

4. Desfăşurarea lucrării

1. Se parcurg noţiunile teoretice din introducerea lucrării;


2. Se lansează programul de aplicaţie;
3. Se introduce textul care urmează a fi codat;
4. Se alege tipul de codare dorit (Huffman, FGK, Vitter);
I. Codarea Huffman
 se observă modul de implementare al algoritmului Huffman, parcurgând
etapele în ordinea paşilor;
 se vizualizează şi se desenează arborele Huffman format;
 algoritmul se reia pentru un nou exemplu, revenind în pagina principală.

22
Transmisiunea digitală a informaţiei. Compresie fără pierderi. Aplicaţii şi lucrări practice.

II. Codarea FGK


 algoritmul se implementează dinamic;
 se observă la fiecare pas noul arbore format şi se desenează arborele
final;
 algoritmul se reia pentru un nou exemplu, revenind în pagina principală.
III. Codarea Vitter
 algoritmul se implementează dinamic;
 se observă la fiecare pas noul arbore format şi se desenează arborele
final;
 algoritmul se reia pentru un nou exemplu, revenind în pagina principală.
5. Se observă şi se notează parametrii obţinuţi în urma celor trei tipuri de
codări (lungimea codului, lungimea medie a codului, entropia sursei şi
eficienţa codării);
6. Codarea se reia, introducând un nou text.

5. Întrebări

1. Cum se realizează compresia de date prin algoritmii de tip Huffman?


2. Care sunt paşii algoritmului FGK?
3. Care sunt paşii algoritmului Vitter?
4. Care sunt deosebirile între modul de formare al arborelui FGK şi al arborelui
Vitter?
5. Care dintre algoritmii studiaţi este recomandat pentru compresia unei surse
staţionare? Dar în cazul în care sursa prezintă aglomerări locale de simboluri (sursă
nestaţionară)? Explicaţi alegerea făcută.
6. Cum ar trebui să arate un text care să poată profita la maximum de această
familie de metode de compresie?
7. Daţi un exemplu de text cu rată de compresie bună.
8. Daţi un exemplu de text cu compresie slabă. Explicaţi alegerea făcută.
9. Rulaţi cei trei algoritmi pentru acelaşi text. Ce observaţi?
10. Comparaţi eficienţa codării Huffman pentru un text cu două caractere
distincte şi pentru un alt text cu 10 caractere distincte, ambele având acelaşi număr
total de caractere. Ce observaţi?
11. Cum se modifică răspunsurile de mai sus în cazul aplicării algoritmilor FGK
şi Vitter?
12. Care dintre cei trei algoritmi este mai eficient şi de ce?

23

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