哈夫曼树的定义:n个叶结点,权分别为w1,w2,···,wn的二叉树中,带权路径长度WPL最小的二叉树叫哈夫曼树(Huffman Tree ), 即:最优二叉树
哈夫曼原理:
1)将字符集中每个字符c出现的频率f(c)作为权值
2)根据给定的权值{w1,w2,···,wn}构造n个二叉树F={T1,T2,···,Tn}, 每个Ti只有一个根结点,权为wi。
3)在F中选取两棵根结点的权值最小的树构成一棵新的二叉树,其根的权值为左右子树根的权值的和。
4)F中删去这两棵树,加上新得的树。
5)重复2)3)直到只剩一棵树。
tips:在实际操作中步骤2其实只选取权值最小的两个构成一个新节点
编码实现:
1:在算法huffmanTree中,编码字符集中每一字符c的频率是f(c)。以f为键值的优先队列Q用在贪心选择时,有效地确定算法当前要合并的2棵具有最小频率的树。
2:一旦2棵具有最小频率的树合并后,产生一棵新树,频率为其合并频率之和,并将新树插入优先队列Q。
3:经过n-1次的合并后,优先队列中只剩下一棵树,即所要求的树T。
代码实现:
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f;
typedef struct HTNode
{
char ch;
unsigned int weight;
unsigned int parent, lchild, rchild;
}HTNode, *HuffmanTree;
HuffmanTree HT;
int w[1024];//字符出现的次数
char str[1024];//存储输入的字符
char out[1024];//输出哈夫曼编码
int n;
//挑选两个出现频路最小且未使用的节点
void Select_Two_HTNode(int pos, int &pos1, int &pos2)
{
int value1, value2;
value1 = value2 = inf;
for(int i = 1; i < pos; ++i)
{
if(HT[i].parent == 0)
{
if(HT[i].weight < value1)
{
int temppos = pos1;
int tempvalue = value1;
pos1 = i;
value1 = HT[i].weight;
if(tempvalue < value2)
{
value2 = tempvalue;
pos2 = temppos;
}
}
else
{
if(HT[i].weight < value2)
{
pos2 = i;
value2 = HT[i].weight;
}
}
}
else
continue;
}
}
void HuffmanCoding()
{
int m = 2 * n - 1; //哈夫曼数节点的数量
HT = (HTNode *)malloc(sizeof(HTNode) * (m + 1));
HuffmanTree p = HT + 1; //第一个节点不用
//初始化已知的n个节点
for(int i = 1; i <= n; ++i, ++p)
{
p->weight = w[i];
p->ch = str[i];
p->parent = p->lchild = p->rchild = 0;
}
//初始化其余节点
for(int i = n + 1; i <= m; ++i, ++p)
p->weight = p->parent = p->lchild = p->rchild = 0;
p = HT + n + 1;//开始合并两个节点
for(int i = n + 1; i <= m; ++i, ++p)
{
int pos1, pos2;
Select_Two_HTNode(i, pos1, pos2);
p->weight = HT[pos1].weight + HT[pos2].weight;
p->lchild = pos1, p->rchild = pos2;
HT[pos1].parent = HT[pos2].parent = i;
}
}
void inPut()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
getchar();
scanf("%c %d", &str[i], &w[i]);
}
// for(int i = 1; i <= n; ++i)
// cout << str[i] << " " << w[i];
}
//深度搜索输出
void outPut(int pos, int i)
{
if(HT[pos].lchild == 0 && HT[pos].rchild == 0)
{
printf("字符 %c 的Huffman编码为 %s\n", HT[pos].ch, out);
}
else
{
out[i] = '0';
outPut(HT[pos].lchild, i + 1);
out[i] = '1';
outPut(HT[pos].rchild, i + 1);
strcpy(out + i, "");
}
}
int main()
{
inPut();
HuffmanCoding();
outPut(2 * n - 1, 0);
}
测试样例:
5
a 1
b 2
c 3
d 4
e 5
输出结果
字符 c 的Huffman编码为 00
字符 a 的Huffman编码为 010
字符 b 的Huffman编码为 011
字符 d 的Huffman编码为 10
字符 e 的Huffman编码为 11
例题:
一道例题 Huffman Coding
标签:编码,哈夫曼,weight,int,HT,Huffman,贪心 From: https://blog.51cto.com/u_16129621/6350094