1. 相关概念:
- 定长编码:
- 类似于ASCII码这种, 每个字符都是定长的编码
- 变长编码:
- 每个字符的编码每个字符的编码长度不相同
- 前缀码:
- 每个字符的编码都不可能是其他字符的前缀
2. 梗概:
- 用根结点到叶结点的路径表示一个编码对象
- 从根结点到叶结点的所走分支的顺序=编码从左到右的顺序
- 习惯上规定分支表示的码:
- 往左走为0
- 往右走为1
3. 哈夫曼编码的特点:
- 前缀码
- 没有二义性
- 频率越高, 编码越短
4. 哈夫曼编码在C语言中的实现:
4.1. 梗概:
- 一个一个叶结点地编码
- 从叶结点倒推回根结点
- 这样路径才唯一, 才找的出来
- 因为往上看, 根结点唯一; 而往下看, 叶结点不唯一
- 需要申请一个临时保存当前叶结点编码的工作空间
- 获得对应结点(权值)的编码
HuffmanCode[对应结点在哈夫曼数组中的下标]
4.2. 代码实现:
typedef char* HuffmanCode[N+1];
void CrtHuffmanCode (HuffmanTree ht, HuffmanCode hc, int n){
//hc为二维数组,储存每个叶结点对应编码
//n为叶结点数
int i,start,c,p;
/*cd数组用于临时保存当前叶结点的编码*/
char *cd;
/*叶结点编码最长不超过总叶结点数量*/
cd = (char*)calloc(n,sizeof(char));
/*因为从叶结点倒退根结点,故从右往左编码*/
cd[n-1]='\0';
for(i=1;i<=n;i++){
/*当前编码的左边界*/
start = n-1;
/*倒退根结点*/
c=i;p=ht[i].parent;
for(;p!=0;){
--start;
/*习惯规定左为0,右为1*/
if(ht[p].LChild==c)cd[start]='0';
else cd[start]='1';
c=p;p=ht[p].parent;
}
/*当前叶结点编码完毕,复制保存编码结果*/
hc[i]=(char*)calloc(n-start,sizeof(char));
strcpy(hc[i],&cd[start]);
}
/*为下一个叶结点编码做准备*/
free(cd);
}