目录
[2.1 Huffman树创建](#2.1 Huffman树创建)
[2.2 Huffman树的编码](#2.2 Huffman树的编码)
[2.3 代码实现Huffman树的创建](#2.3 代码实现Huffman树的创建)
[2.4 代码实现Huffman树的编码](#2.4 代码实现Huffman树的编码)
一、基本知识

路径:一个结点到另一个结点的通路被称为路径;如A结点到F结点之间的通路
路径长度:根到子节点每走一条边,长度 + 1,根节点路径长度为 0;又在一棵树中,规定根结点所在层数为1,那从根结点到第i层结点的路径长度为i-1,F结点的路径长度为3
节点的带权路径长度:(给每一个节点赋予一个新的数值,被称为这个结点的权),根到节点的路径长度 × 节点权重为该节点的带权路径长度;如F结点的带权路径长度为3*5
树的带权路径长度(WPL):为树中所有叶子结点的带权路径长度之和;如上图WPL = 5 * 3 + 2 * 4
等长编码:如ABCD分别用011 010 101 111表示,都是三个bit,是等长编码
变长编码:如在(AABCAADBBCD)A:1表示 B:01表示 C:001表示 次数出现概率高的用较短的编码表示,可以节省空间
前缀码:如A:11 B:110 ,11是110的前缀,这种是不合法前缀码,合法前缀码需任意编码都不是其他编码前缀(如此才能无歧义解码)
哈夫曼树:哈夫曼编码是一种合法的前缀码,同时也是最优变长编码------它不会出现前缀码冲突(不合法),且树的带权路径长度(WPL)最小 (哈夫曼编码一定是合法前缀码)
二、Huffman树编码实现
2.1 Huffman树创建
例:节点A-H、weight[] = {5,29,7,8,14,23,3,11,8}


2.2 Huffman树的编码
2.3 代码实现Huffman树的创建
C
static void selectNode(HuffmanTree tree,int n,int *s1,int *s2)
{
int mini = 0;
// 找到第一个父节点为0的编号
for (int i = 1;i <= n;++i)
{
if (tree[i].parent == 0)
{
mini = i;
break;
}
}
for (int i = 1;i<=n;++i)
{
if (tree[i].parent == 0)
{
if (tree[i].weight < tree[mini].weight)
{
mini = i;
}
}
}
*s1 = mini;
// 开始找第二个最小权值的点
for (int i=1;i<=n;++i)
{
if (tree[i].parent == 0 && i != *s1)
{
mini = i;
break;
}
}
for (int i = 1;i<=n;++i)
{
if (tree[i].parent == 0 && i != *s1)
{
if (tree[i].weight < tree[mini].weight)
{
mini = i;
}
}
}
*s2 = mini;
}
HuffmanTree createHuffmanTree(const int* w, int n)
{
int m = 2*n -1;
// 1.1 申请2n个单元,从1号索引开始存储数据
HuffmanTree tree = malloc(sizeof(HuffmanNode) * (m+1));
if (tree == NULL)
{
return NULL;
}
// 初始化1~2n-1个节点
for (int i = 1;i<=m;++i)
{
tree[i].parent = tree[i].lChild = tree[i].rChild = 0;
tree[i].weight = 0;
}
// 1.2设置初始化权值
for (int i = 1;i<=n;++i)
{
tree[i].weight = w[i-1];
}
int s1,s2;
// 填充n+1下标到m下标的空间
for (int i = n+1;i<=m;++i)
{
// 在[1...i-1]范围内,父节点为0,权值最小的两个点
selectNode(tree,i-1,&s1,&s2);
// 将这2个权值最小的节点,组合到第i个位置上(父节点)
tree[s1].parent = tree[s2].parent = i;
tree[i].lChild = s1;
tree[i].rChild = s2;
tree[i].weight = tree[s1].weight + tree[s2].weight;
}
return tree;
}
2.4 代码实现Huffman树的编码
C
HuffmanCode* createHuffmanCode(HuffmanTree tree, int n)
{
// 生成n个字符的编码表,每个表项里保存编码的空间首地址
HuffmanCode *codes = malloc(sizeof(HuffmanCode) * n);
if (codes == NULL)
{
return NULL;
}
memset(codes,0,sizeof(HuffmanCode) * n);
// 每求一个字符时,倒序构建,n个节点,树的高度最高是n,编码个数最多为n
char *temp = malloc(sizeof(char) * n);
int start;
int p; // 记录第i个位置的父节点
int pos; // 记录当前位置i
for (int i = 1;i <= n;++i)
{
start = n-1; // temp、start组合使用,从后往前
temp[start] = '\0'; // n-1位置放'\0'
pos = i;
p = tree[i].parent;
while (p) // 第i个位置的父节点存在
{
--start;
// 该父节点左孩子是pos(i),则'0',否则是右孩子'1'
temp[start] = tree[p].lChild == pos ? '0':'1';
pos = p;
p = tree[p].parent;
}
// huffman树节点1-n,codes数组下标0-n-1
codes[i-1] = malloc(sizeof(char) * (n-start));
strcpy(codes[i-1],&temp[start]); // 将temp中存的编码复制,至codes[i-1]位置
}
free(temp);
return codes;
}
编码过程:
两数组:**codes:用来存编码 、temp:是临时数组,与start变量从数组尾到头编码
两变量: pos:存当前位置 、 p:存当前位置的父节点
每经历一个while循环,就将temp临时数组中存的内容复制到codes中
如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

