# 哈夫曼编码
哈夫曼树构造过程:
- 在 n 个权值中选出两个最小的权值,对应的两个结点组成一个新的二叉树,且新二叉树的根结点的权值为左右孩子权值的和;
- 在原有的 n 个权值中删除那两个最小的权值,同时将新的权值加入到 n–2 个权值的行列中,以此类推;
- 重复 1 和 2 ,直到所以的结点构建成了一棵二叉树为止,这棵树就是哈夫曼树。
哈弗曼树编码及译码关键函数如下:
1、哈弗曼树构造函数
//创建哈弗曼树
void createhuff(huff &ht,int n,int *f)
{
int s1,s2;
if(n<=1)return;
int m=2*n-1;
ht=new htnode[m+1];
for(int i=1; i<=m; ++i)
{
ht[i].parent=0;
ht[i].lchild=0;
ht[i].rchild=0;
}
for(int i=1; i<=n; i++)
{
ht[i].weigth=f[i-1];
}
for(int i=n+1; i<=m; ++i)
{
select(ht,i-1,s1,s2);
ht[s1].parent=i;
ht[s2].parent=i;
ht[i].lchild=s1;
ht[i].rchild=s2;
ht[i].weigth=ht[s1].weigth+ht[s2].weigth;
}
}
2、哈夫曼编码
//哈夫曼编码
typedef char **huffcode;
void createhuffcode(huff ht,huffcode &hc,int n)
{
hc=new char*[n+1];
char cd[n];
cd[n-1]='\0';
for(int i=1; i<=n; i++)
{
int start=n-1;
int c=i;
int f=ht[i].parent;
while(f!=0)
{
--start;
if(ht[f].lchild==c)
cd[start]='0';
else
cd[start]='1';
c=f;
f=ht[f].parent;
}
hc[i]=new char[n-start];
strcpy(hc[i],&cd[start]);
}
}
3、选择两个最小值函数:select函数
//select算法
void select(huff &HT,int n,int &s1,int &s2)
{
int minum;
for(int i=1; i<=n; i++)
{
if(HT[i].parent == 0)
{
minum = i;
break;
}
}
for(int i=1; i<=n; i++)
{
if(HT[i].parent == 0)
if(HT[i].weigth <= HT[minum].weigth)
minum = i;
}
s1 = minum;
for(int i=1; i<=n; i++)
{
if(HT[i].parent == 0 && i != s1)
{
minum = i;
break;
}
}
for(int i=1; i<=n; i++)
{
if(HT[i].parent == 0 && i != s1)
if(HT[i].weigth <= HT[minum].weigth)
minum = i;
}
s2 = minum;
}
4、求结点权重
//求权重
void getFrequency(char *ch,int *f)
{
f[58]= {0};
for(int i=0; i<strlen(ch); i++)
{
int num=ch[i]-'A';
f[num]++;
}
//求哈夫曼结点数
for(int i=0; i<58; i++)
{
if(f[i]!=0)
len++;
}
}
5、 哈夫曼译码
//哈夫曼译码
void HuffmanDecoding(huff HT, char *a, char *cha, char *b, int n)
{
//a用来传入二进制编码,b用来记录译出的字符,cha是与哈夫曼树的叶子对应的字符,n是字符个数相当于cha数组的长度
int q = 2 * n-1; //q初始化为根结点的下标
int k = 0; //记录存储译出字符数组的下标
for (int i = 0; i<strlen(a); i++)
{
if (a[i] == '0')
{
q = HT[q].lchild;
}
else if (a[i] == '1')
{
q = HT[q].rchild;
}
if (HT[q].lchild == 0 && HT[q].rchild == 0)
{
b[k++] = cha[q-1];
q = 2 * n-1;
}
}
b[k] = '\0';
}