前缀编码
每个字符的编码都不是另一个的前缀
比如:A: 01 B: 010这样就不行,如果是AABB字符集时,编出来的码是0101010,可能翻译成AAA
哈夫曼编码
哈夫曼树的特性非常适合前缀编码
因为字符集中的字符只会出现在树的叶子节点
树从上往下左按0右1读,只有当前节点的母节点会是它的前缀,叶子节点之间不可能是谁的母节点。
且哈夫曼树带权路径最小
思路
按权值构建哈夫曼树,字符权值长度为n,哈夫曼树节点数为2n-1。
创建一个长度为2n-1的数组,把原有的权值填到数组中,数组的长度设为n
w[]={7,9,6,12,35,1,2,6,47};
hf[]={7,9,6,12,35,1,2,6,47,0,0,....};
找出两个最小权值,相加赋值给到hf[n],并设置子节点为这两个最小权值的下标,相应的这两个权值的母节点为n,n+1,给一个标志表示这两数比较过,下次递归将不再比较。递归重复此操作直到n+1大于2n-1;
然后遍历所有叶子节点,依次从下往上读,读到根节点,左为0,右为1
代码
构建哈弗曼树
typedef struct Huffman {
int w;
int flag;//判断是否比较过
int code[10];//伪码
int k;//码长
int lchild,rchild,parent;
}HuffmanNode;
typedef struct HuffmanT {
HuffmanNode *hn;
int len;
}HuffmanTree;//初始化哈夫曼树
int init_HuffmanTree(HuffmanTree* root, int w[], int n) {
root->hn = (HuffmanNode*)malloc(sizeof(HuffmanNode) * (2*n-1));
if (root->hn == NULL) return 0;
root->len = n;
for (int i = 0; i < n; i++)
{
root->hn[i].w = w[i];
root->hn[i].parent = -1;
root->hn[i].flag = 0;
}
return 1;
}
//创建哈夫曼数
int creat_HuffmanTree(HuffmanTree *root,int n) {
//最小数下标
int min1 = 0, min2 = 0;
//找两个最小的数
for (int i = 0; i < n; i++)
{
if (root->hn[min1].flag == 1) min1++;
if (root->hn[i].flag==0&&root->hn[min1].flag==0&&min1!=i) {
if (root->hn[min1].w >= root->hn[i].w) min1 = i;
}
}
root->hn[min1].flag = 1;
for (int i = 0; i < n; i++)
{
if (root->hn[min2].flag == 1) min2++;
if (root->hn[i].flag == 0 && root->hn[min2].flag == 0 && min2 != i) {
if (root->hn[min2].w >= root->hn[i].w) min2 = i;
}
}
root->hn[min2].flag = 1;
//构建树
root->hn[n].lchild = min1;
root->hn[n].rchild = min2;
root->hn[n].flag = 0;
root->hn[n].parent = -1;
root->hn[n].w = root->hn[min2].w + root->hn[min1].w;
root->hn[min2].parent = root->hn[min1].parent = n;
n = n + 1;//递归
if (n < (root->len * 2) - 1) creat_HuffmanTree(root, n);return 1;
}
编码和读码
//生成码
void creat_HuffmanCode(HuffmanTree* root,int n) {
int i,k;
for (int j = 0; j < n; j++)
{
i = j;
k = 0;
while (i < 2*n-2) {
if (root->hn[i].parent!=-1) {
if (root->hn[root->hn[i].parent].lchild == i) {
root->hn[j].code[k] = 0;
k++;
i = root->hn[i].parent;
}
if (root->hn[root->hn[i].parent].rchild == i) {
root->hn[j].code[k] = 1;
k++;
i = root->hn[i].parent;
}
}
}
root->hn[j].k = k;
}
}
//查看码
void look_Code(HuffmanNode hd[],int n) {
for (int i = 0; i < n; i++)
{
printf("%d 的码为:",hd[i].w);
for (int k = hd[i].k-1; k >= 0; k--)
{
printf("%d",hd[i].code[k]);
}
printf("\n");
}
}