Sunteți pe pagina 1din 4

Structuri de Date L A B O R A T O R 8b

Heap binar si arbori Huffman Un minheap este un vector cu urmatoarele proprietati: - Valoarea fiecarui nod este mai mica sau egala cu valorile din nodurile fii, deci valoarea minima se afla in radacina arborelui. - Valoarea din pozitia k are fiul stanga in pozitia 2*k si fiul dreapta in pozitia 2*k+1. Parintele valorii din pozitia k este in pozitia k/2. Exemple de vectori minheap de lungime 4 construiti cu valorile 1,2,3,4 : 1,3,2,4 1 / \ 3 / 4 4 2 / 3 2 1,2,3,4 1 / \ 3 / 2 1,2,4,3 1 / \ 4

Adaugarea unui nou element la un vector Heap se face in prima pozitie libera (de la sfarsitul vectorului), dupa care se ridica acest element in vector astfel ca sa se respecte conditia de minheap. addPQ (a,n,x) { k=++n; // k este prima pozitie libera pune x in pozitia k repeta cat timp k>1 si a[k/2]>a[k] { // daca a[k] mai mic ca parintele sau schimba a[k] cu a[k/2] k=k/2 } } La extragerea si eliminarea valorii minime dintr-un minheap (primul element) se aduce apoi ultimul element in prima pozitie, dupa care se corecteaza vectorul pentru respectarea conditie de heap (prin propagarea in jos a valorii din prima pozitie, cat timp este necesar): delPQ (a,n){ x=a[1] a[1]=a[n--] heapify(1) return x } // prima valoare e minima // se aduce ultima valoare la inceput // refacere heap

Operatia "heapify" se poate exprima recursiv sau iterativ: se determina repetat valoarea maxima dintre elementele a[k], a[2*k] si a[2*k+1] si, daca e nevoie, se aduce acest maxim in pozitia k. Notand cu a vectorul si cu n dimensiunea sa, forma recursiva este: heapify(a,n,k) { // ajustare arbore cu radacina in k m=indmin (k) // indice minim dintre a[k],a[2k],a[2k+1] daca m != k atunci { schimba a[k] cu a[m] heapify(m) // ajustare subarbore cu radacina in m }

} Varianta iterativa a functiei anterioare este: heapify(a,n,k) { repeta cat timp e necesar un interschimb { m=indmin (k) // indice maxim dintre a[k],a[2k],a[2k+1] daca m != k atunci{ schimba a[k] cu a[m] k=m } } } Observatie: inainte de a folosi indicii 2*k si 2*k+1 se verifica daca exista acesti indici in vector (daca sunt inferiori lui n). indmin (a,n,k) { st=2*k, dr=st+1 m=k // indice val. minima (initial k) daca st<=n si a[st] < a[m] atunci m=st // minim este a[st] daca dr<=n si a[dr] < a[m] atunci m=dr // minim este a[dr] return m } 1. Sa se defineasca o structura "PQ" cu vectorul heap a si dimensiunea sa n (vector cu dimensiune fixa). Sa se scrie si sa se verifice urmatoarele functii pentru un minheap de intregi: void initPQ (PQ & q); void addPQ (PQ & q,int x); int delPQ (PQ & q); void printPQ (PQ q); int emptyPQ (PQ q); // // // // // creare heap q de capacitate n adauga x la minheap scoate si sterge element minim din heap afisare heap ca vector daca vectorul heap este gol

Sa se verifice cu programul urmator: int main () { PQ pq; int x[10]={3,8,2,9,7,1,5,4,6,0}; int i; initPQ (pq); for (i=0;i<9;i++){ addPQ (pq,x[i]); printPQ(pq); } while ( ! emptyPQ (pq)){ printPQ (pq); printf ("min=%d\n",delPQ(pq)); } getchar(); } Compresia Huffman Metoda de codificare Huffman a unui sir de caractere inlocuieste fiecare octet printr-un cod cu numar variabil de biti, astfel incat caracterele

care apar mai frecvent sa aiba coduri mai scurte. Metoda Huffman are 2 etape: - Construirea unui arbore binar in care fiecare caracter apare ca o frunza; - Parcurgerea arborelui pentru generarea codurilor Huffman ale caracterelor. In arborele creat caracterele de codificat se afla in frunze, iar calea de la radacina la o frunza (cu 0 pentru ramificare la stanga si 1 pentru ramificare la dreapta) reprezinta codul Huffman al caracterului respectiv. 2. Sa se defineasca tipul structura CF care reuneste un caracter si frecventa lui de aparitie. Sa se defineasca tipul structura Nod care contine o variabila CF si pointeri catre cei doi fii (stanga,dreapta). Sa se scrie o functie de creare a unui nod de arbore cu fii cunoscuti: Nod* make ( CF x, Nod* left, Nod* right); Sa se modifice definitia tipului PQ pentru o coada cu prioritati realizata ca min-heap de pointeri Nod*, prioritatea fiind frecventa din Nod. Sa se modifice si functiile pentru operatii cu coada PQ ca sa lucreze cu poiteri Nod*. Sa se verifice operatiile cu coada folosind programul urmator: erifice operatiile cu coada folosind programul urmator: int main () { CF a[]= { {'a',36},{'b',14},{'c',12},{'d',10},{'e',20},{'f',8} }; PQ q; initPQ(q); for (int i=0;i<6;i++) addPQ(q,make (a[i],0,0)); // adauga la coada while ( ! emptyPQ(q)){ Nod* p= delPQ(q); printf("%c=%d\n",p->x.ch,p->x.fr); } getchar(); } 3. Sa se scrie si sa se verifice o functie "build" pentru crearea unui arbore Huffman pe baza unui vector de structuri CF: Nod* build (CF[] a, int n); // n=dimensiunea vectorului a

Arborele este construit treptat de jos in sus, folosindu-se o coada cu prioritati PQ ordonata dupa numarul de aparitii, folosind algoritmul urmator: ch='0' // caractere pentru noduri nou create initializare coada PQ repeta { citeste caracter si frecventa creare nod de arbore cu caracter si frecventa adauga la coada PQ adresa nod creat } repeta cat timp coada PQ contine cel putin doua elemente { scoate un element din coada PQ in "left" scoate un element din coada PQ in "right" f = suma frecvente din left si right; creare nod cu perechea (++ch,f) si fii left,right adauga la coada PQ adresa nod creat }

scoate din coada PQ adresa r si afiseaza arbore cu radacina r Verificarea se va face prin afisarea prefixata cu indentare a arborelui: // afisare arbore void write (Nod* r,int ns) { if (r != 0) { printf ("%*c %c(%2d)\n", ns,' ',r->x.ch, r->x.fr); write (r->st,ns+3); write (r->dr,ns+3); } } Afisarea codurilor Huffman pe baza aborelui se va face cu functia urmatoare: // proc. de generare si afisare coduri din arbore void afcod (Nod* r, int cod, int len) { // la primul apel cod=len=0 char s[10]; // aici se depune codul H if (r==NULL) return; if ( r->st==NULL && r->dr==NULL) // daca nod frunza printf ("%c : %0*s \n", r->x.ch,len,itoa(cod,s,2)); else { afcod ( r->st, 2*cod+0,len+1); afcod ( r->dr, 2*cod+1,len+1); } }

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