在此本人用一个简单的例子来介绍Huffmantree。
a ,b,c,d,e频率分别为2、4、1、5、3,首先来建立Huffmantree.a、b、c、d、e分别代表此Hufmantree的5个叶子节点,刚开始时这5个节点代表5棵树,这5棵树组成森林。取森林中频率最小的两棵树,合成一棵二叉树,该二叉树的根节点的频率为这两个叶子结点的频率之和,将这两个频率最小的树从森林中删掉,新的树加入森林,一次重复此步骤,知道建立一棵Huffmantree.
以此例为例子,建立Huffamtree的各个步骤如下:
最后建立的Huffmantree如下:
在Huffmantree中,结点的左边为编码‘0’,右边为编码‘1’,故在该Huffmantree中,a的编码为001,b的编码为10,c的编码为000,d的编码为11,e的编码为01。
下面用c语言来实现Huffman编码:
程序的主要思路如下:
首先定义一个结构体数组,结构体的成员有:数据内容,频率,节点的父母亲,节点的右、左儿子。Huffmantree有5个叶子节点,故Huffmantree共有25-1个节点,所以结构体数组的的长度可为25(序号为0的节点未使用)。1~5号节点为叶子节点,其余的节点为Huffmantree的内部节点,根据Huffmantree的建立规则,建立对应的Huffmantree,然后根据Huffmantree求出对应的叶子节点的Huffman编码。
具体代码代码如下
#include <iostream>
#include<stdlib.h>
#include<string.h>
typedef struct {
int weight;
int parent;
int lchild;
int rchild;
}HTNode,*HTree;
typedef char** Huffmancode;
int Min(HTree HT, int n) { //选择最小的节点
int i=0;
while (HT[i].parent!= 0)//选出HT中第一个节点的parent不为0的节点
i++;
int min_weight = HT[i].weight;
int min = i;
for (; i < n; i++) {
if (min_weight >=HT[i].weight&&HT[i].parent==0) {
min_weight = HT[i].weight;
min = i;
}
else
continue;
}
HT[min].parent = 1;// 避免进行第二次进行选择时再次选到同一个最小节点
return min;
}
void Select_min(HTree HT, int k, int& m1, int& m2) { //选出最小节点及次小的节点
m1 = Min(HT, k);
m2 = Min(HT, k);
}
HTree Creating_Huffmantree(int* w, int n) {//构造Huffmantree
HTree HT = (HTNode*)malloc(2 * n * sizeof(HTNode));
if (HT == NULL) {
printf("内存分配不成功!\n");
exit(1);
}
else {
int i = 1;//Huffmantree数组的下标从1开始
for (; i <= n; i++) {//初始化Huffmantree
HT[i].weight = *w;
w++;
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
for (; i < 2 * n; i++) {
HT[i].weight = 0;
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
}
int min1, min2;//用于存放最小的两个节点的序号
for (int j = n + 1; j < 2 * n; j++) {
Select_min(HT, j, min1, min2);
HT[min1].parent = j;
HT[j].lchild = min1;
HT[min2].parent = j;
HT[j].rchild = min2;
HT[j].weight = HT[min1].weight + HT[min2].weight;
}
return HT;
}
int Depth(HTree HT,int index) {//返回叶子结点的深度
int temp=index;
int Dcount = 0;
while (HT[temp].parent != 0) {//求序号为i的叶子节点的路径长
temp = HT[temp].parent;
Dcount++;
}
return Dcount;
}
int WPL(HTree HT,int n) {//从叶子节点开始求Huffmantree的带权路径长度
int tatal_weight = 0;
for (int i = 1; i <= n; i++) {
tatal_weight += HT[i].weight * Depth(HT, i);
}
return tatal_weight;
}
void Huffmancoding(HTree HT,Huffmancode HC, int n) {//为Huffmantree 编码
HC = (char**)malloc(n * sizeof(char*));
if (HC == NULL) {
printf("内存分配不成功!\n");
exit(1);
}
else {
for (int i = 1; i <= n; i++) {
int H = Depth(HT, i);
char* s = (char*)malloc((H + 1) * sizeof(char));//用于存储序号为i的叶子节点的逆序编码
if (s == NULL) {
printf("内存分配不成功!\n");
exit(1);
}
else {
int t1 = i;
int t2 = HT[t1].parent;
for (int j = 0; j < H; j++) {
if (t1 == HT[t2].lchild)
s[H-j-1] = '0';
else if (t1 == HT[t2].rchild)
s[H-j-1] = '1';
else {
printf("编码错误!\n");
exit(1);
}
t1 = t2;
t2 = HT[t2].parent;
}
s[H] = '\0';
HC[i] = (char*)malloc((H + 1) * sizeof(char));
if (HC[i] == NULL) {
printf("内存分配不成功!\n");
exit(1);
}
else
strcpy_s(HC[i],H+1, s);
printf("%s\n", HC[i]);
free(s);
}
}
}
}
int main() {
int w[5] = { 2,4,1,5,3 };//以此为a,b,c,d,e的频率
int n = 5;
HTree T = NULL;
T = Creating_Huffmantree(w,n);
for (int i = 1; i < 2 * n; i++) {
printf("%d\n", i);
printf("weight=%d\n", T[i].weight);
printf("parent=%d\n", T[i].parent);
printf("lchild=%d\n", T[i].lchild);
printf("rchild=%d\n", T[i].rchild);
}
printf("Huffmantree总的带权路径长度为:%d\n", WPL(T, n));
Huffmancode HC=NULL;
printf("叶子结点a,b,c,d,e的Huffman编码依次如下:\n");
Huffmancoding(T, HC, n);
return 0;
}
运行结果如下:

来源:CSDN
作者:XY德
链接:https://blog.csdn.net/weixin_44335707/article/details/104180266