定义:带权路径长度WPL最小的二叉树(在编写哈夫曼编码时用到的特殊二叉树)
构造过程:
其实就是每次在权值集合中选两个最小结点的组成新树,然后新树的根节点是二者的权值之和,将刚刚两个从集合中删掉,将新树的根节点添加进去,一直到只有一棵树位置。(一般权值小的为左子树)
作用:用来实现哈夫曼编码,以及后续的解码,使用哈夫曼编码来压缩我们在网络传输中的文件
实现原理:在计算机中我们的数据最终都是通过0、1来存储发送的,那么尽管是不同的语言,都有出现频率较高的字符,比如中文中的 “的、了、在、有” 等,英文中的 “a, e, i, o, u” 等元音字母,使用哈夫曼编码可以使这些出现频率较高的字符的编码位数更短,假设字符 A 原本的编码是 ’‘0000“,经过哈夫曼编码之后成为 ”01“ (具体情况具体分析,这里只是举例),这样在数据很多的情况下我们就可以节省很大的空间(所以平时我们编写代码时也应该站在处理数据很大的角度来提升程序的效率)。
假设发送的数据为“BADCADFEED”,六个字母的频率:A 27, B 8, C 15, D 15, E 30, F 5
原本的编码:
用哈夫曼树构造哈夫曼编码:
哈夫曼编码:
解码:
1、编码非0即1,长短不等的话非常容易混淆,所以设计这种长短不等的代码,我们必须保证任一字符的编码都不是另一个字符编码的前缀,这种编码称为前缀编码。仔细观察构造出的哈夫曼编码就是前缀编码。
2、在解码时还需要用到哈夫曼树,即发送方和接收方必须要约定好同样的哈夫曼编码规则,从而成功解码。一般规定哈夫曼树的左分支代表0,右分支代表1。 构造哈夫曼树代码:
//构造哈夫曼树
void CreateHaff(int *weight,int n,HFNode* phfnode)
{
int i, j;
int min1, min2;//最小值和次小值
int min1x, min2x;//最小值和次小值的下标
for (int i = 0; i < 2 * n - 1; ++i)
{//2*n-1 是哈夫曼树总的结点个数
if (i < n)
{//给前n个结点赋值
phfnode[i].weight = weight[i];
}
else
{//后面的结点是后续的新结点,开始将权值置0,后续权值为其
//左右孩子的权值之和
phfnode[i].weight = 0;
}
//初始化每个结点的信息
phfnode[i].leftindex = -1;
phfnode[i].rightindex = -1;
phfnode[i].parentindex = -1;
phfnode[i].flag = 0;
}
for (i = 0; i < n - 1; i++)
{
min1 = min2 = 65535;
min1x = min2x = -1;
//在数组中查找最小的和次小的
for (j = 0; j < n + i; j++)
{
//比最小值小
if (phfnode[j].weight < min1 && phfnode[j].flag == 0)
{
min2 = min1;
min2x = min1x;
min1 = phfnode[j].weight;
min1x = j;
}
//比次小值小
else if(phfnode[j].weight < min2 && phfnode[j].flag == 0)
{
min2 = phfnode[j].weight;
min2x = j;
}
}
phfnode[n + i].weight = min1 + min2;
phfnode[n + i].leftindex = min1x;
phfnode[n + i].rightindex = min2x;
phfnode[min1x].parentindex = n + i;
phfnode[min1x].flag = 1;
phfnode[min2x].parentindex = n + i;
phfnode[min2x].flag = 1;
}
}
构造哈夫曼编码代码:
void HaffCode(HFNode* phfnode, int n, char code[5][20])
{
//char code[5][20]用来存放各个字符的编码
int i;
char temp[20] = {0};
int child;
int parent;
int end = 20 - 2;//end代表的是下标,19下标是\0所以从18下标开始存放编码
for (i = 0; i < n; ++i)//计算n个结点的编码
{
child = i;
parent = phfnode[child].parentindex;
end = 20 - 2;
temp[20 - 1] = '\0';
while (parent != -1)
{
if (child == phfnode[parent].leftindex)
temp[end] = '0';
else if (child == phfnode[parent].rightindex)
temp[end] = '1';
end--;
child = parent;
parent = phfnode[child].parentindex;
}
//由于最后end--所以拷贝时要+1
strcpy(code[i], temp + end + 1);
}
}