1.数据结构设计
Huffman树中没有度为1的节点。n0=n2+1;
1棵树有n个叶子节点的Huffman树共有2n-1个节点,故可存储在大小为2n-1的一位数组中。
原因:
求编码需要从叶子节点出发走一条从叶子到根的路径。
Weight | Parent | Lchild | Rchild |
权值 | 双亲节点下标 | 左 | 右 |
译码需从根节点出发走一条到叶子结点的路径。
2.结构定义
typedef struct htnode
{
unsigned int Weight;
unsigned int Parent,Lchild,Rchild;
}HTNode;
3.Huffmand的生成
//Huffmand的生成
void Create_Huffman(unsigned n,HTNode HT[],unsigned m){
/*创建一颗叶子结点树为n的Huffman树*/
unsigned int w;int k,j;
for(k=1;k<m;k++){
if(k<=n){
cout<<"\nPlease Input Weight :w=?";
cin>>w;
HT[k].Weight=w;
}/*输入时,所有叶子结点都有权值*/
else
HT[k].Weight=0;/*非叶子结点没有权值*/
HT[k].Parent=HT[k].Lchild=HT[k].Rchild=0;
}//初始化向量HT
for(k=n+1;k<m;k++){
unsigned w1=32564,w2=w1;
/*w1,w2分别保存权值最小的两个权值*/
int p1=0,p2=0;
/*p1,p2保存两个最小权值的下标*/
for(j=1;j<=k-1;j++){
if(HT[k].Parent==0){/*尚未合并*/
if(HT[j].Weight<w1){
w2=w1;p2=p1;
w1=HT[j].Weight;
p1=j;
}
else if(HT[j].Weight<w2){
w2=HT[j].Weight;
p2=j;
} /*找到权值最小的两个值及其下标*/
}
}
HT[k].Lchild=p1;HT[k].Rchild=p2;
HT[k].Weight=w1+w2;
HT[p1].Parent=k;HT[p2].Parent=k;
}
}
根据出现的频度(权值)Weight,对叶子节点的Huffman编码有两种方式:
(1)从叶子节点到根逆向处理 ,求得每个叶子结点对于字符的Huffman编码。
(2)从根节点开始遍历整颗二叉树,求得每个叶子 节点对应字符的Huffman编码。
由Huffman树生成知,n个叶子结点的树共有2n-1个结点,叶子结点存储在数组HT中下标值为1-n.
(1)编码是叶子结点的编码,只需对数组HT[1...n]的n个权值进行编码。
(2)每个字符的编码不同,但编码的最大长度是n。
4.求编码
求编码时先设置一个通用的字符的指针变量,求得编码后再复制。
代码:
void Huff_coding(unsigned n,Hnode HT[],unsigned m)
/*m应为n+1,编码的最大长度n加1*/
{
int k,sp,fp;
char *cd,*HC[m];
cd=(char *)malloc(m*sizeof(char));
/*动态分配求编码的工作空间*/
cd[n]='\0';
for(k=1;k<n+1;k++)/*逐个求字符的编码*/{
sp=n;p=k;fp=HT[k].parent;
for(;fp!=0;p=fp,fp=HT[p].parent)
/*从叶子结点到根逆向求编码*/
if(HT[fp].parent==Lchild) cd[--sp]='0' ;
else cd[--sp]='1';
HC[k]=(char *)malloc((n-sp)*sizeof(char));
/*为第k个字符分配保存编码的空间*/
trcpy(HC[k],&cd[sp]);
}
free(cd);
}