Huffman编码的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Huffman编码的问题相关的知识,希望对你有一定的参考价值。

将字符串bababecbdcdedebeebba进行Huffman编码,将之编码成二进制串,并计算平均码长

huffman算法的VC++实现
最小堆头文件minheap.h:
template <class Type> class MinHeap
public:
MinHeap(int maxSize);//常成员函数不能修改this指向的内容
MinHeap(Type arr[],int n);
~MinHeap()delete[]heap;
int Insert(const Type &x);
int RemoveMin(Type &x);//用参数作返回值
Type DeleteMin();
int IsEmpty()constreturn CurrentSize==0;
int IsFull()constreturn CurrentSize==MaxHeapSize;
void MakeEmpty()CurrentSize=0;
private:
enumDefaultSize=10;
Type *heap;
int CurrentSize;
int MaxHeapSize;
void FilterDown(const int start,const int end);
void FilterUp(int start);
;
template <class Type> MinHeap<Type>::MinHeap(int maxSize)//根据给定大小maxSize,建立堆对象
MaxHeapSize=DefaultSize<maxSize?maxSize:DefaultSize;//确定堆大小
heap=new Type[MaxHeapSize];//创建堆空间
CurrentSize=0;//初始化

template <class Type> MinHeap<Type>::MinHeap(Type arr[],int n)//根据给定数组中的数据和大小,建立堆对象
MaxHeapSize=DefaultSize<n?n:DefaultSize;
heap=new Type[MaxHeapSize];
heap=arr;//数组传送
CurrentSize=n;//当前堆大小
int currentPos=(CurrentSize-2)/2;//最后非叶
while(currentPos>=0)//从下到上逐步扩大,形成堆
FilterDown(currentPos,CurrentSize-1);//从currentPos开始,到CurrentSize-1为止, 调整
currentPos--;


template <class Type> int MinHeap<Type>::Insert(const Type&x)//在堆中插入新元素x
if(CurrentSize==MaxHeapSize)//堆满
cout<<"堆已满"<<endl;
return 0;

heap[CurrentSize]=x;//插在表尾
FilterUp(CurrentSize);//向上调整为堆
CurrentSize++;//堆元素增一
return 1;

template <class Type> void MinHeap<Type>::FilterUp(int start)//从start开始,向上直到0,调整堆
int j=start,i=(j-1)/2;//i是j的双亲
Type temp=heap[j];
while(j>0)
if(heap[i].root->data.key<=temp.root->data.key)break;
elseheap[j]=heap[i];j=i;i=(i-1)/2;

heap[j]=temp;

template <class Type> void MinHeap<Type>::FilterDown(const int start,const int end)
int i=start,j=2*i+1;
Type temp=heap[i];
while(j<=end)
if(j<end&&heap[j].root->data.key>heap[j+1].root->data.key)j++;
if(temp.root->data.key<=heap[j].root->data.key)break;
else
heap[i]=heap[j];
i=j;
j=2*j+1;


heap[i]=temp;

template <class Type> int MinHeap<Type>::RemoveMin(Type &x)
if(!CurrentSize)
cout<<"Heap empty"<<endl;
return 0;

x=heap[0];
heap[0]=heap[CurrentSize-1];
CurrentSize--;
FilterDown(0,CurrentSize-1);
return 1;

template <class Type> Type MinHeap<Type>::DeleteMin()//不可以用引用,因为堆扩展时会覆盖返回的元素,引用会出错
if(!CurrentSize)
cout<<"Heap empty"<<endl;
return 0;

Type x=heap[0];
heap[0]=heap[CurrentSize-1];
CurrentSize--;
FilterDown(0,CurrentSize-1);
return x;

huffman树类huffman.h
#include"minheap.h"
#include<string.h>
template <class Type> struct NodeData
Type symbol;//结点代表的符号
int key;//记录频数
char num;//结点编码
;
template <class Type> class ExtBinTree;
template <class Type> class Element
friend class ExtBinTree<Type>;
friend class MinHeap<ExtBinTree<Type> >;
public:
Element<Type>(Type na='^',int f=0,char n='0')
data.key=f;
data.symbol=na;
data.num=n;
parent=leftChild=rightChild=NULL;

private:
NodeData<Type> data;
Element<Type>*parent,*leftChild,*rightChild;
;
template <class Type> class ExtBinTree
friend class MinHeap<ExtBinTree<Type> >;
public:
ExtBinTree(int n=0,Type *s=NULL,Type *name=NULL,Element<Type> *l=NULL):
root(l),num(n),str(s)
na=new Type[n];
na=name;
fr=new int[n];
for(int i=0;i<n;i++)fr[i]=0;
if(str!=NULL)Fre();

void Modify(ExtBinTree<Type> *bt1,ExtBinTree<Type> *bt2)
root->parent=NULL;
root->leftChild=(*bt1).root;
root->rightChild=(*bt2).root;
(*bt1).root->parent=(*bt2).root->parent=root;
(*bt1).root->data.num='0';
(*bt2).root->data.num='1';
root->data.key=(*bt1).root->data.key+(*bt2).root->data.key;

void HuffmanTree();//构造哈夫曼树
Element<Type>* Find(Type item);//寻找结点的函数
char* Coding(Type item);//编码函数
void Fre();//计算字符频数的函数
void DeCoding(char s[]);//译码函数
int *GetFr()return fr;//返回字符出现的频数
double Entropy(int m);//求序列的熵或编码的平均码长
private:
Element<Type> *root;//扩充二叉树的根
int num;//输入的字符种类数
Type *str;//输入的字符串
Type *na;//存放各种字符
int *fr;//各种字符的频数
;
template <class Type> void ExtBinTree<Type>::HuffmanTree()
int n(0),*f=new int[num];
char *s=new char[num];
for(int i=0;i<num;i++)
if(fr[i]!=0)
f[n]=fr[i];
s[n]=na[i];
n++;


ExtBinTree<Type> *Node=new ExtBinTree<Type>[n];
for(i=0;i<n;i++)
Node[i].root=new Element<Type>(s[i],f[i]);
MinHeap<ExtBinTree<Type> > hp(Node,n);
ExtBinTree<Type> first,second;
for(i=0;i<n-1;i++)//建立霍夫曼树的过程,做n-1趟
hp.RemoveMin(first);//选根权值最小的树
hp.RemoveMin(second);//选根权值次小的树
root=new Element<Type>;
Modify(&first,&second);//建新的根结点
hp.Insert(*this);//形成新树插入


template <class Type> Element<Type>* ExtBinTree<Type>::Find(Type item)//寻找值为item的结点
Element<Type>*p=root,**s=new Element<Type>*[num+1];
int top=-1;
while(!(p==NULL&&top==-1))
while(p!=NULL)
s[++top]=p;
p=p->leftChild;

if(top!=-1)
p=s[top--];
if(p->data.symbol==item)return p;
p=p->rightChild;


return NULL;

template <class Type> char* ExtBinTree<Type>::Coding(Type item)
Element<Type>*p=Find(item);
if(p==NULL)
cerr<<"符号未找到!";
return NULL;

char *s=new char[num];
int i=-1;
while(p!=root)
s[++i]=p->data.num;
p=p->parent;

char *c=new char[i+2];
for(int j=0;j<=i;j++)
c[j]=s[i-j];
c[j]='\0';
return c;

template <class Type> void ExtBinTree<Type>::DeCoding(char s[])
int i=0;
Element<Type>*p=root;
while(s[i]!='\0')
if(s[i]=='0')
p=p->leftChild;
if(p->data.symbol!='^')
cout<<p->data.symbol;
p=root;


else
p=p->rightChild;
if(p->data.symbol!='^')
cout<<p->data.symbol;
p=root;


i++;


template <class Type> void ExtBinTree<Type>::Fre()
int i=0;
while(*(str+i)!='\0')
for(int j=0;j<num;j++)
if(*(str+i)==na[j])fr[j]++;
i++;


template <class Type> double ExtBinTree<Type>::Entropy(int m)
double ent=0;
int n(0);
while(str[n]!='\0')n++;
if(m==0)//计算符号序列熵
for(int i=0;i<num;i++)
if(fr[i]!=0)
ent+=-double(fr[i])/n*log(double(fr[i])/n)/log(2);

else if(m==1)//计算平均码长
for(int i=0;i<num;i++)
if(fr[i]!=0)
ent+=double(fr[i])/n*strlen(Coding(na[i]));

else
cout<<"错误调用!\n";
return 0;

return ent;

主程序:
#include<iostream.h>
#include<fstream.h>
#include<math.h>
#include"huffman.h"
#define DN 26
#define SIZE 200
void main()
char *sym="abcdefghijklmnopqrstuvwxyz";
char s[SIZE],a[20],c;
char *d=new char[5*SIZE];
ifstream in;
lp: cout<<"是否从文件导入?y/n:";
cin>>c;
switch(c)
case 'y':cout<<"输入路径(以txt结尾):";
cin>>a;
in.open(a);
in>>s;
in.close();
cout<<s<<endl;
break;
case 'n':cout<<"请输入符号序列:";
cin>>s;
break;
default:cerr<<"无效操作,请重新输入!";
goto lp;

ExtBinTree<char> h(DN,s,sym);
h.HuffmanTree();
int i=0;
cout<<"编码:\n";
while(s[i]!='\0')
cout<<h.Coding(s[i]);
i++;

cout<<endl;
int n=i;
cout<<"各字符出现的频率及码字:\n";
int *f=h.GetFr();
for(i=0;i<DN;i++)
if(f[i]!=0)
cout<<sym[i]<<':'<<double(f[i])/n<<'\t'<<h.Coding(sym[i])<<endl;
cout<<"输入符号熵:"<<h.Entropy(0)<<endl;
cout<<"编码平均码长:"<<h.Entropy(1)<<endl;
i=0;
cout<<"译码:\n";
while(s[i]!='\0')
if(i==0)d=strcpy(d,h.Coding(s[i]));
else d=strcat(d,h.Coding(s[i]));
i++;

h.DeCoding(d);
cout<<endl;
参考技术A 先分析个字符的权值:
a=3,b=7,c=2,d=3,e=5
生成一棵霍夫曼树,得到各字符的编码:
a=110,b=0,c=1111,d=1110,e=10
平均码长为46/15本回答被提问者采纳
参考技术B wd@Klutz-wd ~/c
$ gcc huffman.c

wd@Klutz-wd ~/c
$ ./a.exe
bababecbdcdedebeebba
* * * * * * ** * ** ** ** * ** * * * * * * *
* * * * * * * * * * * * * * *

*代表1,平均码长自己做一下除法。

以上是关于Huffman编码的问题的主要内容,如果未能解决你的问题,请参考以下文章

算法Huffman编码(数据结构+算法)

POJ - 1521 Entropy (Huffman编码)

Huffman编码的问题

Huffman树与Huffman编码

数据结构之哈弗曼编码的(Huffman Coding)加密解密压缩

基于Huffman编码的文件压缩项目