目录
一、哈夫曼编码的由来
1、在远程通讯中,要将待传字符转换成由二进制的字符串如下图所示:
如上图所示若将每个字符都用同样位数的二进制数来表示的话会产生浪费。但如果将编码设计为长度不等的二进制编码,即让待传字符串中出现次数较多的字符采用尽可能短的编码,则转换的二进制字符串便可能减少。如下图所示:
而哈夫曼编码刚好满足前缀编码的要求,并却能够使电文的总长度最短。
二、构造哈夫曼编码的方法
1、统计字符集中每个字符在电文中出现的平均概率(概率越大,要求编码越短)。
2、利用哈夫曼树的特点:权越大的叶子离根越近;将每个字符的概率值作为权值,构造哈夫曼树。则概率越大的结点,路径越短。
3、在哈夫曼树的每个分支上标上0或1:
结点的左分支标0,右分支标1
把从根到每个叶子的路径上的标号连接起来,作为该叶子代表的字符的编码。
三、哈夫曼编码的构造实例
四、哈夫曼编码的性质
由上图的例子可知以下两点:
1、因为没有一片树叶是另一片树叶的祖先, 所以每个叶子结点的编码就不可能是其它叶子结点编码的前缀,因此哈夫曼编码是前缀码。
2、因为哈夫曼树的带权路径长度最短,所以可以保证字符编码的总长最短。
3、哈夫曼编码是前缀码,并且是最优前缀码。
五、哈夫曼编码的算法实现
1、哈夫曼编码的存储结构如下图所示:
1、哈夫曼编码的存储结构如下图所示:
2、哈夫曼编码的算法描述
void CreatHuffmanCode(HuffmanTree HT, HuffmanCode &HC, int n){
//从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
HC=new char *[n+1]; //分配n个字符编码的头指针矢量
cd=new char [n]; //分配临时存放编码的动态数组空间
cd[n-1]= '\0' ; //编码结束符
for(i=1;i<=n; + +i){ //逐个字符求哈夫曼编码
start=n-1; c=i; f=HT[].parent;
while(f!=0){ //从叶子结点开始向上回溯,直到根结点
--start; //回溯一次start向前指一个位置
if (HT[f].lchild==c) cd[start]='0'; //结点c是的左孩子, 则生成代码0
else cd[start]= '1'; //结点c是的右孩子, 则生成代码1
c=f; f=HT[f].parent; //继续向上回溯
} //求出第i个字符的编码
HC[i]= new char [n-start]; //为第i个字符串编码分配空间
strcpy(HC[i],&cd[start]); //将求得的编码从临时空间cd复制到HC的当前行中
delete cd; //释放临时空间
} //CreatHuffanCode
六、哈夫曼编码的应用举例——文件的编码和解码
1、编码的步骤
①输入各字符及其权值
②构造哈夫曼树——HT[i],最终不同的字符都有一个叶子表示。
③进行哈夫曼编码——HC[j]
④查HC[i] ,得到各字符的哈夫曼编码
2、解码的步骤
①构造哈夫曼树
②依次读入二进制码——从第一个二进制数开始,若为0,则走向左孩子;若为1,则走向右孩子
④一旦到达某叶子时,即可译出字符
⑤然后再从根出发继续译码,直到结束
典型列子如下图所示: