Arbori Huffman si Arbori Ponderati in C++
Aici e un pic mai mult, programul contine doua clase ArboreHuffman si ArborePonderat si cu ajutorul lor realizeaza o forma foarte simpla de codificare (programul poate fi modificat pentru a fi un arhivator). Ca deobicei codul este in C++ si foloseste alocare dinamica a memoriei.
demo.cpp
// demo.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include "liste.h"
#include "ArborePonderat.h"
#include "ArboreHuffman.h"
void AdaugaNodPonderatInLista(LISTA<NodPonderat*> & noduri, char * cheie)
{
bool ok = true;
for(int i=0; i<noduri.lungime(); i++)
if(strcmp(cheie, noduri[i]->cheie) == 0)
{
ok = false;
noduri[i]->pondere++;
}
if(ok)
{
NodPonderat* nodNou = new NodPonderat(cheie, 1);
noduri.AdaugaInceput(nodNou);
}
}
void AdaugaNodHuffmanInLista(LISTA<NodHuff*> & noduri, char cheie)
{
bool ok = true;
for(int i=0; i<noduri.lungime(); i++)
if(cheie == noduri[i]->cheie)
{
ok = false;
noduri[i]->pondere++;
}
if(ok)
{
NodHuff* nodNou = new NodHuff(cheie, 1);
noduri.AdaugaInceput(nodNou);
}
}
bool Citeste(LISTA<NodPonderat*> & noduri)
{
ifstream fin("ponderat.txt", ios::in);
if(fin.fail())
return false;
char buf[512];
while(!fin.eof())
{
fin>>buf;
AdaugaNodPonderatInLista(noduri, buf);
}
return true;
}
bool Citeste(LISTA<NodHuff*> & noduri)
{
ifstream fin("huffman.txt", ios::in);
if(fin.fail())
return false;
char c;
while(!fin.eof())
{
fin>>c;
AdaugaNodHuffmanInLista(noduri, c);
}
return true;
}
void main()
{
// ponderat
/*
cout<<endl<<"Ponderat: "<<endl<<endl;
LISTA<NodPonderat*> noduriPond;
if(!Citeste(noduriPond))
return;
ArborePonderat arbore;
arbore.CreazaArbore(noduriPond);
arbore.Nivele();
*/
// huffman
LISTA<NodHuff*> noduriHuff;
if(!Citeste(noduriHuff))
return;
cout<<endl<<"Huffman: "<<endl<<endl;
ArboreHuffman huff;
huff.CreazaArbore(noduriHuff);
cout<<"Arborele huffman: ";
huff.Nivele();
cout<<endl<<"Codurile huffman: "<<endl;
huff.AfiseazaCod();
char c;
cin>>c;
}
ArboreHuffman.h
// ArboreHuffman.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>
#include "liste.h"
using namespace std;
typedef struct NodHuff
{
char cheie;
int pondere;
NodHuff *st;
NodHuff *dr;
NodHuff(char cheieNoua, int ponderea) {
cheie = cheieNoua;
pondere = ponderea;
st = dr = NULL; }
}NodHuff;
class ArboreHuffman
{
private:
NodHuff **frunze;
NodHuff *rad;
int nrNoduri;
int nrElemente;
void DetCod(NodHuff *rad, char cod[512], int poz);
public:
ArboreHuffman(void);
~ArboreHuffman(void);
void Nivele();
void CreazaArbore(LISTA<NodHuff*> & listaNoduri);
void AfiseazaCod();
};
ArboreHuffman.cpp
// ArboreHuffman.cpp
#include "ArboreHuffman.h"
#include "ArborePonderat.h"
ArboreHuffman::ArboreHuffman(void)
{
rad = NULL;
frunze = NULL;
nrElemente = nrNoduri = -1;
}
ArboreHuffman::~ArboreHuffman(void)
{
if(frunze != NULL)
delete []frunze;
}
void ArboreHuffman::CreazaArbore(LISTA<NodHuff*> & noduri)
{
NodHuff *min1, *min2, *aux;
int i;
nrElemente = noduri.lungime();
nrNoduri = 2*noduri.lungime() - 1;
frunze = new NodHuff*[nrElemente];
for(i=0; i<noduri.lungime(); i++)
frunze[i] = noduri[i];
while(noduri.lungime() > 1)
{
min1 = noduri[0];
min2 = noduri[1];
for(i=2; i<noduri.lungime(); i++)
if(noduri[i]->pondere < min1->pondere)
{
min1 = noduri[i];
if(min1->pondere < min2->pondere)
{
aux = min1;
min1 = min2;
min2 = aux;
}
}
// cream un sungraf cu cele 2 noduri ca subgraf stang si drept
aux = new NodHuff('*', min1->pondere + min2->pondere);
aux->st = min1;
aux->dr = min2;
// stergem minimele si adaugam nodul nou
noduri.Sterge(min1);
noduri.Sterge(min2);
noduri.AdaugaSfarsit(aux);
}
// ar trebui sa avem un singur element in lista, radacina
rad = noduri[0];
noduri.Sterge();
}
void ArboreHuffman::Nivele()
{
// verificari
if(rad == NULL)
{
cout<<"Arborele e gol!\n";
return;
}
// variabile auxiliare
NodHuff ** coada = new NodHuff*[nrNoduri]; // retine nodurile parcurse in latime
int *nivele = new int[nrNoduri]; // retine nivelul pe care se afla fiecare nod
NodHuff *x;
int inc, sf; // inceputul si sfarsitul cozii
// initializam nivelele, coada.
nivele[0] = 1; // nivelul nodurilor
coada[0] = rad; // primul nod din coada
inc = sf = 0; // inceputul si sfasitul cozii
// cata vreme avem noduri in coada
cout<<"\nNivel 1: ";
while(inc <= sf)
{
// afisam primul nod din coada
x = coada[inc];
cout<<x->cheie<<" ";
// bagam fii ultimului nod in coada
// si completam nivelul nodurilor
if(x->st)
{
coada[++sf] = x->st;
nivele[sf] = nivele[inc]+1;
}
if(x->dr)
{
coada[++sf] = x->dr;
nivele[sf] = nivele[inc]+1;
}
// scoatem primul nod din coada
inc++;
// afisam nivelul daca este diferit de nivelul nodului precedent
if(nivele[inc] != nivele[inc-1] && inc <= sf)
cout<<"\nNivel "<<nivele[inc]<<": ";
}
// stergem memoria folosita pentru retinerea cozii si a nivelului nodului
delete[] coada;
delete[] nivele;
}
void ArboreHuffman::DetCod(NodHuff *rad, char cod[], int poz)
{
if(rad == NULL)
return;
if(rad->cheie != '*')
{
cout<<"cheie: "<<rad->cheie<<" cod: "<<cod<<endl;
return;
}
cod[poz+1] = '\0';
cod[poz] = '0';
DetCod(rad->st, cod, poz+1);
cod[poz] = '1';
DetCod(rad->dr, cod, poz+1);
cod[poz] = '\0';
}
void ArboreHuffman::AfiseazaCod()
{
int t = 0;
for(int i=0; i<nrElemente; i++)
{
cout<<"cheia: "<<frunze[i]->cheie<<" apare de "<<frunze[i]->pondere<<endl;
t += frunze[i]->pondere;
}
cout<<"total: "<<t<<endl;
//
char cod[512];
cod[0] = '\0';
DetCod(rad, cod, 0);
}
ArborePonderat.h
// ArborePonderat.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>
#include "liste.h"
using namespace std;
typedef struct NodPonderat
{
char *cheie;
int pondere;
NodPonderat *st;
NodPonderat *dr;
NodPonderat(char *cheieNoua, int ponderea) {
cheie = new char[strlen(cheieNoua)+1];
strcpy(cheie, cheieNoua);
pondere = ponderea;
st = dr = NULL; }
~NodPonderat() { if(cheie) delete []cheie; }
}NodPonderat;
class ArborePonderat
{
private:
NodPonderat *rad;
int nrNoduri;
public:
ArborePonderat(void);
~ArborePonderat(void);
void Nivele();
void CreazaArbore(LISTA<NodPonderat*> & listaNoduri);
};
ArborePonderat.cpp
// ArborePonderat.cpp
#include "ArborePonderat.h"
ArborePonderat::ArborePonderat(void)
{
}
ArborePonderat::~ArborePonderat(void)
{
}
void ArborePonderat::CreazaArbore(LISTA<NodPonderat*> & noduri)
{
NodPonderat *min1, *min2, *aux;
int i;
nrNoduri = 2*noduri.lungime() - 1;
while(noduri.lungime() > 1)
{
for(int j=0; j<noduri.lungime(); j++)
cout<<noduri[j]->cheie<<" ";
cout<<endl;
min1 = noduri[0];
min2 = noduri[1];
for(i=2; i<noduri.lungime(); i++)
if(noduri[i]->pondere < min1->pondere)
{
//cout<<noduri[i]->cheie<<" ";
min1 = noduri[i];
if(min1->pondere < min2->pondere)
{
aux = min1;
min1 = min2;
min2 = aux;
}
}
// cream un sungraf cu cele 2 noduri ca subgraf stang si drept
char buf[512];
strcpy(buf, min1->cheie);
strcat(buf, min2->cheie);
aux = new NodPonderat(buf, min1->pondere + min2->pondere);
aux->st = min1;
aux->dr = min2;
// stergem minimele si adaugam nodul nou
noduri.Sterge(min1);
noduri.Sterge(min2);
noduri.AdaugaSfarsit(aux);
}
// ar trebui sa avem un singur element in lista, radacina
rad = noduri[0];
noduri.Sterge();
}
void ArborePonderat::Nivele()
{
// verificari
if(rad == NULL)
{
cout<<"Arborele e gol!\n";
return;
}
// variabile auxiliare
NodPonderat ** coada = new NodPonderat*[nrNoduri]; // retine nodurile parcurse in latime
int *nivele = new int[nrNoduri]; // retine nivelul pe care se afla fiecare nod
NodPonderat *x;
int inc, sf; // inceputul si sfarsitul cozii
// initializam nivelele, coada.
nivele[0] = 1; // nivelul nodurilor
coada[0] = rad; // primul nod din coada
inc = sf = 0; // inceputul si sfasitul cozii
// cata vreme avem noduri in coada
cout<<"\nNivel 1: ";
while(inc <= sf)
{
// afisam primul nod din coada
x = coada[inc];
cout<<x->cheie<<" ";
// bagam fii ultimului nod in coada
// si completam nivelul nodurilor
if(x->st)
{
coada[++sf] = x->st;
nivele[sf] = nivele[inc]+1;
}
if(x->dr)
{
coada[++sf] = x->dr;
nivele[sf] = nivele[inc]+1;
}
// scoatem primul nod din coada
inc++;
// afisam nivelul daca este diferit de nivelul nodului precedent
if(nivele[inc] != nivele[inc-1] && inc <= sf)
cout<<"\nNivel "<<nivele[inc]<<": ";
}
// stergem memoria folosita pentru retinerea cozii si a nivelului nodului
delete[] coada;
delete[] nivele;
}
liste.h - ar trebuie rearanjat un pic codul
deasemenea atentie la folosirea listei, suntem in C++, si se poate sa apara rezultate
nesteptate in cazul folosirii pointerilor
// liste.h
//****************************************************************************
// LISTE
//****************************************************************************
#pragma once
//****************************************************************************
// clasa pentru retinerea unei liste cu elemente de tipul ELEMENT
//****************************************************************************
template<class ELEMENT>
class LISTA
{
private:
// nod este o structura necesara doar in interiorul clasei lista
typedef struct NOD
{
ELEMENT data;
NOD *urm;
}NOD;
// inceputul listei
NOD *inceput;
// sfarsitul listei
NOD *sfarsit;
// nodul curent folosit la iterarea listei
int indexPrec;
NOD *nodPrec;
// lungime
int numarElemente;
// permite elemente duplicate
bool permisDuplicat;
// cauta un element in lista
bool CautaElement(ELEMENT pEl, NOD **outPrecedent, NOD **outCurent);
// Cauta un nod dupa pozitie in lista
// daca nu este gasit nici un nod pe pozitia specificata
// functia returneaza NULL, iar altfel adresa nodului
NOD* CautaNodDupaPozitie(int pozitie)
{
NOD* p = inceput;
int index = 0;
while(index != pozitie && p != NULL)
{
index++;
p = p->urm;
}
return p;
}
// sterge nod
void StergeNod(NOD* pNod)
{
delete pNod;
numarElemente--;
}
// creaza un nod nou
NOD* CreazaNod(ELEMENT pEl)
{
// alocam memorie
NOD* pNod = new NOD;
// completam informatia din nod
pNod->urm = NULL;
pNod->data = pEl;
numarElemente++;
// returnam nodul creat
return pNod;
}
public:
// constructor si destructor
LISTA(bool permiteDuplicat = true);
~LISTA(void);
// adauga un element nou in lista
bool AdaugaInceput(ELEMENT el);
bool AdaugaSfarsit(ELEMENT el);
// operator
ELEMENT & operator[](int index);
// lungimea
int lungime() { return numarElemente; }
// returneaza pozitia elementului cautat
int CautaPozitia(ELEMENT el);
// sterge un element
ELEMENT Sterge(ELEMENT el);
// sterge toate elementele
void Sterge();
};
//****************************************************************************
// este initializata lista
//****************************************************************************
template <class ELEMENT>
LISTA<ELEMENT>::LISTA(bool permiteDuplicat)
{
permisDuplicat = permiteDuplicat;
inceput = sfarsit = NULL;
nodPrec = NULL;
indexPrec = -1;
numarElemente = 0;
}
//****************************************************************************
// destructor sunt sterse toate elementele listei
//****************************************************************************
template <class ELEMENT>
LISTA<ELEMENT>::~LISTA(void)
{
Sterge();
}
//****************************************************************************
// functia sterge un element al listei
// returneaza elementul sters
//****************************************************************************
template <class ELEMENT>
ELEMENT LISTA<ELEMENT>::Sterge(ELEMENT el)
{
NOD *precedent;
NOD *curent;
ELEMENT elSters;
// daca gasim nodul
if(CautaElement(el, &precedent, &curent))
{
// trebuie sters primul nod
if(precedent == NULL)
{
// verificam daca stergem nodul pentru parcurgere
if(this->nodPrec == inceput)
this->nodPrec = curent->urm;
// modificam legaturile
inceput = curent->urm;
if(inceput == NULL)
sfarsit = NULL;
}
else
{
// verificam daca stergem nodul pentru parcurgere
if(this->nodPrec == curent)
this->nodPrec = inceput;
// modificam legaturile
precedent->urm = curent->urm;
// poate trebuie sa modificam sfarsitul
if(curent == sfarsit)
sfarsit = precedent;
}
// stergem nodul
elSters = curent->data;
StergeNod(curent);
// nodul a fost sters
return elSters;
}
// nodul nu exista
return elSters;
}
//****************************************************************************
// functia sterge toate elementele listei
//****************************************************************************
template <class ELEMENT>
void LISTA<ELEMENT>::Sterge()
{
NOD *curent;
// cata vreme mai exista noduri
while(inceput != NULL)
{
// se stocheaza nodul curent
curent = inceput;
// nodul urmator
inceput = inceput->urm;
// este sters nodul curent
StergeNod(curent);
}
//nodul curent devine null
this->nodPrec = NULL;
this->indexPrec = -1;
}
//****************************************************************************
// functia cauta un element in lista
// returneaza pozitia lui, daca nu este in lista returneaza -1
//****************************************************************************
template <class ELEMENT>
int LISTA<ELEMENT>::CautaPozitia(ELEMENT el)
{
int poz = 0;
// iteram lista de la inceput
NOD *start = inceput;
while(start != NULL)
{
// verificam daca am gasit elementul
if(start->data == el)
return poz;
// avansam in cautare
start = start->urm;
poz++;
}
// nodul nu exista
return -1;
}
//****************************************************************************
// functia adauga un element in lista la inceput
// returneaza true daca elementul a fost adaugat cu succes
//****************************************************************************
template <class ELEMENT>
bool LISTA<ELEMENT>::AdaugaInceput(ELEMENT el)
{
NOD* precedent;
NOD* curent;
// verificam daca avem voie sa avem elemente duplicate
if(!permisDuplicat)
{
// cautam elementul
bool bExista = CautaElement(el, &precedent, &curent);
// verificam daca nodul exista deja in lista
if(bExista)
return false;
}
// cream un nod nou
NOD* nodNou = CreazaNod(el);
nodNou->urm = inceput;
inceput = nodNou;
// daca am adaugat primul nod
if(inceput->urm == NULL)
sfarsit = inceput;
return true;
}
//****************************************************************************
// functia adauga un element in lista la sfarsit
// returneaza true daca elementul a fost adaugat cu succes
//****************************************************************************
template <class ELEMENT>
bool LISTA<ELEMENT>::AdaugaSfarsit(ELEMENT el)
{
NOD* precedent;
NOD* curent;
// verificam daca avem voie sa avem elemente duplicate
if(!permisDuplicat)
{
// cautam elementul
bool bExista = CautaElement(el, &precedent, &curent);
// verificam daca nodul exista deja in lista
if(bExista)
return false;
}
// cream un nod nou
NOD* nodNou = CreazaNod(el);
nodNou->urm = NULL;
if(sfarsit != NULL)
{
sfarsit->urm = nodNou;
sfarsit = nodNou;
}
else
sfarsit = inceput = nodNou;
return true;
}
//****************************************************************************
// operatorul [] returneaza elementul de pe pozitia index
//****************************************************************************
template <class ELEMENT>
ELEMENT & LISTA<ELEMENT>::operator [](int index)
{
// verificam datele de intrare
if(index < 0)
index = 0;
else if(index >= numarElemente)
index = numarElemente-1;
// index se incrementeaza
if(indexPrec+1 == index && indexPrec != -1)
{
indexPrec++;
nodPrec = nodPrec->urm;
return nodPrec->data;
}
// nu avem index precedent
nodPrec = CautaNodDupaPozitie(index);
indexPrec = index;
return nodPrec->data;
}
//****************************************************************************
// functia cauta un element in lista
//
// daca elementul este gasit functia returneaza true iar prec este adresa
// nodului precedent nodului curent, iar curent este adresa nodului curent
//
// daca elementul nu este gasit functia returneaza false iar prec si curent
// sunt nodurile intre care poate fi inserat elementul cautat
//****************************************************************************
template <class ELEMENT>
bool LISTA<ELEMENT>::CautaElement(ELEMENT pEl, NOD **outPrecedent, NOD **outCurent)
{
// nu vrem sa lucram cu pointer dublu
NOD *precedent = NULL;
NOD *curent = NULL;
// pointer spre informatia din elementul curent
ELEMENT data;
// verificam daca avem o lista goala
if(inceput == NULL)
{
*outPrecedent = precedent;
*outCurent = curent;
return false;
}
// daca lista nu e goala
curent = inceput;
while(curent != NULL)
{
// informatia este stocata in data
data = curent->data;
// cautam elementul
if(data != pEl)
{
// nu e elementul cautat, caontinuam
precedent = curent;
curent = curent->urm;
}
else
{
// s-a ajuns la un elementul cautat
*outCurent = curent;
*outPrecedent = precedent;
// daca elementul este egal cu cel cautat returnam true, altfel false
return true;
}
}
// lista a fost parcursa, dar elementul nu a fost gasit
*outCurent = curent;
*outPrecedent = precedent;
return false;
}
Comments
ai dreptate alin, ii fain codul
yes
Super codu!!
merci de 10