哈夫曼编码(数据结构)
哈夫曼编码,又称霍夫曼编码,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)
#include<iostream>
#include<stdio.h>
#include<string.h> //因为使用了strcpy字符串函数
#include<stdlib.h>
typedef struct{ //哈夫曼树的储存 //可以储存在一个一维数组里
int weight; //结点的权值
int parent,lchild,rchild; //结点的双亲,左右孩子的下标
}HTNode,*HuffmanTree; //动态分配数组储存哈夫曼树
typedef char **HuffmanCode;
void Select(HuffmanTree HT,int len,int &s1,int &s2) //优先级的判断
{
int i,min1=0x3f3f3f3f,min2=0x3f3f3f3f;//先赋予最大值
for(i=1;i<=len;i++)
{
if(HT[i].weight<min1&&HT[i].parent==0)
{
min1=HT[i].weight;
s1=i;
}
}
int temp=HT[s1].weight;//将原值存放起来,然后先赋予最大值,防止s1被重复选择
HT[s1].weight=0x3f3f3f3f;
for(i=1;i<=len;i++)
{
if(HT[i].weight<min2&&HT[i].parent==0)
{
min2=HT[i].weight;
s2=i;
}
}
HT[s1].weight=temp;//恢复原来的值
}
void CreateHuffmanTree(HuffmanTree &HT,int n) //构建哈夫曼树
{int s1,m,s2,i; //变量的初始化
if(n<=1) return; //叶子数必须大于2
m=2*n-1; //n个叶子有2n-1个结点
HT=new HTNode[m+1]; //0号单元未用,所以需要动态分配m+1个单元,HT[m]表示根结点
for(i=1;i<=m;++i){ //将1到m号单元的双亲,左孩子,右孩子的下标都初始化为0
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;}
printf("请输入前%d个单元的叶子结点的权值:",n); //输入前n个单元的叶子节点的权值
for(i=1;i<=n;++i)
scanf("%d",&HT[i].weight);
for(i=n+1;i<=m;++i){ //通过n-1次的选择,删除,和合并来创建哈夫曼树
Select(HT,i-1,s1,s2); //在HT[]数组中选择两个其双亲域权值最小的结点,并返回他们在HT中的序号s1和s2
HT[s1].parent=i;
HT[s2].parent=i; //得到新结点i,从森林中删除s1,s2的双亲域由0改为i
HT[i].lchild=s1;
HT[i].rchild=s2; //s1,s2分别作为i的左孩子和右孩子
HT[i].weight=HT[s1].weight+HT[s2].weight; //i的权值为左右孩子的权值之和
}
}
void CreateHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n){ //从叶子到根逆向求每一个字符的哈夫曼编码,储存在编码表HC中
char* cd;
int i,start,c,f; //变量及指针的定义
HC=new char*[n+1]; //分配储存n个字符编码表的空间
cd=new char[n]; //分配临时存放每个字符编码的动态数组空间
cd[n-1]='\0'; //编码结束符
for(i=1;i<=n;i++){ //逐个字符求哈夫曼编码
start=n-1; //start开始指向最后,及编码结束的的位置
c=i;f=HT[i].parent; //f指向结点c的双亲结点
while(f!=0){ //从叶子结点开始向上回溯,直到根节点
--start; //回溯一次start向前一个位置
if(HT[f].lchild==c) cd[start]='0'; //结点c是f的左孩子,则生成代码0
else cd[start]='1'; //结点c是f的右孩子,则生成1
c=f;
f=HT[f].parent; //继续向上回溯
} //求出第i个字符的编码
HC[i]=new char [n-start]; //为第i个字符编码分配空间
strcpy(HC[i],&cd[start]); //将求得的编码从临时空间cd复制到HC的当前行中
}
delete cd; //释放临时空间
}
void show(HuffmanTree HT,HuffmanCode HC) //输出对应的哈夫曼编码
{
for(int i=1;i<=sizeof(HC)+1;i++)
printf("%d编码为%s\n",HT[i].weight,HC[i]);
}
int main()
{ HuffmanTree HT; //分配一个哈夫曼树
HuffmanCode HC; //分配一个编码表
int n;
printf("请输入有多少个叶子结点");
scanf("%d",&n);
CreateHuffmanTree(HT,n);
CreateHuffmanCode(HT,HC,n);
show(HT,HC);
return 0;
}