写在前面:
这一讲我们来学习一个比较有趣的树 —— 哈夫曼树,在许多非常知名的算法里也出现了哈夫曼树,这一讲我们就好好来唠唠什么是哈夫曼树。
前置概念
概念一:什么是结点路径的长度
从根结点到该结点的路径上的连接数。

例如上图(下面将会用到),从结点 28 到结点 2 的连接数为 3 。
概念二:什么是树的路径长度
就是树的每个叶子结点的路径长度之和,上图的树的路径长度就为 3 + 3 + 3 + 3 + 1 = 13 。
概念三:什么是结点的带权路径长度
结点的路径长度与结点权值的乘积。
概念四:什么是树的带权路径长度 WPL
就是树的所有叶子结点的带权路径长度之和。
应用场景
在数据膨胀、信息爆炸的今天,数据压缩的意义不言而喻。谈到数据压缩,就不能不提赫夫曼(Huffman)编码,赫夫曼编码是首个实用的压缩编码方案,即使在今天的许多知名压缩算法里,依然可以见到赫夫曼编码的影子。
另外,在数据通信中,用二进制给每个字符进行编码时不得不面对的⼀个问题是如何使电稳总长最短且不产生二义性。根据字符出现频率,利用赫夫曼编码可以构造出一种不等长的二进制,使编码后的电文长度最短,且保证不产生二义性。
当有了以上概念以后,我们就可以用WPL去判断一颗二叉树的性能。WPL的值越小,二叉树的性能越优。
哈夫曼树的构造
(1)给出我们要构造的结点权值。

(2)找出两个最小的权值,创建双亲结点,并且其权值等于这两个最小的权值结点之和。将这两个结点移出后续的大小判断,并将新创建的结点加入后续的大小判断。

(3)不断地重复上述操作。



//找到两个最小的权值(这里为了方便大家理解,就分开找两个最小值了)
void select(HuffmanTree huffmanTree[], int n, int &s1, int &s2) {
int min;
//遍历全部的结点,找出一个单结点
for (int i = 1; i <= n; i++) {
if (huffmanTree[i].parent == 0) {
min = i;
break;
}
}
//继续遍历全部结点,找出权值最小的单结点
for (int i = 1; i <= n; i++) {
if (huffmanTree[i].parent == 0) {
if (huffmanTree[i].weight < huffmanTree[min].weight) {
min = i;
}
}
}
s1 = min;
//进行和上面相同的操作,找到第二小的结点
for (int i = 1; i <= n; i++) {
if (huffmanTree[i].parent == 0 && i != s1) {
min = i;
break;
}
}
for (int i = 1; i <= n; i++) {
if (huffmanTree[i].parent == 0 && i != s1) {
if (huffmanTree[i].weight < huffmanTree[min].weight) {
min = i;
}
}
}
s2 = min;
}
//构建哈夫曼树
void

本文介绍了哈夫曼树的概念、路径长度、带权路径长度及其在数据压缩和通信编码中的应用。详细讲解了哈夫曼树的构造过程,通过C++代码展示了如何构建哈夫曼树及生成哈夫曼编码。最后,提供了从叶子结点到根的哈弗曼编码求解方法。
最低0.47元/天 解锁文章
3844

被折叠的 条评论
为什么被折叠?



