数据结构——哈夫曼树

理解数据结构:树的路径、带权路径与哈夫曼编码
文章介绍了树的基本概念,包括路径、路径长度和带权路径长度,特别强调了哈夫曼树的定义和构建过程,以及如何通过哈夫曼树生成哈夫曼编码。通过示例详细解释了从节点到节点的路径、权值计算以及哈夫曼树的构建步骤和编码规则。

路径

路径与长度的概念

以一颗最简单的树作为例子:
在这里插入图片描述
在一棵树里面,从一个节点到另一个节点的路径,称之为这棵树的路径
例如B到H的路径为:
B->E->I
注意:一个节点到另一个节点的路径可以不止有一条

那么路径的长度就是一个节点到另一个节点之间所经历的树枝
例如:从B到I的路径长度为2,因为B->E->I中有两个“->”符号
注意:路径的长度并不是路径之间有几个节点就是多少,路径的长度指的是树枝的个数而不是节点的个数

带权路径长度

计算带权路径长度之前,我们必须给树的每一个节点赋予一个特殊的意义,一般我们会是数字,而这个数字就成为这个节点的,带权路径长度就是路径长度×权
还是用上面这颗树举例子:
在这里插入图片描述
正如每个节点上的蓝色的字体一样,蓝色的字体就是这个节点的权
例如求从A到I的带权路径长度:
A到I的路径长度为:3 I的权为9
则A到I的带权路径长度为3*9=27

树的带权路径和

依旧以上面的那棵树作为例子,还是一样的蓝色的字代表节点的权
树的带权路径和的概念是:树的叶子节点的带权路径和的和
先分析上面那棵树的叶子节点为:D、H、I、F、G
他们的路径长度分别为:2、3、3、2、2
他们的权分别为:4、8、9、6、7
则整棵树的带权路径和为:24 + 38 + 39 + 26 + 2*7 = 8 + 24 + 27 + 12 + 14 = 32 + 27 + 26 = 85

哈夫曼树

哈夫曼树的定义:

根据百度百科的定义:哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。

哈夫曼树的构建

哈夫曼树的构建通常是给定几个节点并且给定这几个节点所代表的特殊数值,要我们排出这颗哈夫曼树的结构
哈夫曼树构建的精髓在于每次选择权最小的两个节点构成一颗子树,并且将构成的子树的根重新按照从小到大的顺序放在原本的节点选项中,重复这个过程,最后得到的树就叫做哈夫曼树
我们以数字 2 3 6 7 10 19 21 32 作为例子

下面是第一步,先找到权值最小的两个节点2和3,构成一颗子树5-2-3,并且将这颗子树的根5 按照顺序放在原本的数列中
在这里插入图片描述
第二步骤,找到该数列中此时最小的两个节点5和6,组合成新的一颗子树,并且按照顺序放在数列中,把这颗子树的根作为数列中的一部分:
在这里插入图片描述
第三步:找到此时最小的两个权值7和10,并且组成一颗新的子树放在其中:
在这里插入图片描述
第四步:找到此时最小的两个权值11和17,构成一颗新的子树,并且将根节点放入其中
在这里插入图片描述
第五步:找到此时最小的两个权值19和21,组成一颗新的子树并且按照顺序放入其中
在这里插入图片描述
第六步:找到此时两个最小的28和32组成一颗子树并且按照顺序放入数列中
在这里插入图片描述
最后一步:将剩下的两颗子树组成为一颗子树,并且按照顺序排好
在这里插入图片描述

哈夫曼编码

哈夫曼编码遵从顺着哈夫曼树的路径,如果路径经过的节点是往左边走,则在树枝上面标记0,如果经过的路径是往右走,则在树枝的上面标记1
还是用一开始的哈夫曼树作为例子:
在这里插入图片描述
我们根据往左走为0,往右走为1的规则给这颗哈夫曼树的树枝上标记上标号:
在这里插入图片描述
接下来我们开始读取哈夫曼编码,哈夫曼编码的读取根据只需要读取从根节点开始,到需要读取的节点路径上经过的树枝的记号
下面举几个例子:
B的编码为:0
D的编码为:00
H的编码为:010
F的编码为:10
G的编码为:11

哈夫曼编码是数据结构中的一种重要编码方式,具有以下特点和相关信息: ### 性质 - **前缀编码**:哈夫曼编码是前缀编码。它是根到叶子路径上的编码序列,由于的特点,若路径A是另一条路径B的最左部分,则B经过了A,那么A的终点一定不是叶子。而哈夫曼编码对应路径的终点一定为叶子,所以任一哈夫曼码都不会与任意其他哈夫曼编码的前缀部分完全重叠[^1]。 - **最优前缀编码**:对于包含n个字符的数据文件,分别以它们的出现次数为权值构造哈夫曼,利用该对应的哈夫曼编码对文件进行编码,能使该文件压缩后对应的二进制文件的长度最短。因为哈夫曼的带权路径长度最短,故字符编码的总长最短[^1][2]。 ### 算法实现 以下是从叶子到根逆向求每个字符的哈夫曼编码的算法实现代码: ```python # 假设这里已经有HuffmanTree和HuffmanCode的定义 def CreateHuffmanCode(HT, HC, n): # 分配n个字符编码的头指针矢量 HC = [None] * (n + 1) # 分配临时存放编码的动态数组空间 cd = [''] * n # 编码结束符 cd[n - 1] = '\0' for i in range(1, n + 1): start = n - 1 c = i f = HT[i].parent while f != 0: # 回溯一次start向前指一个位置 start -= 1 if HT[f].lchild == c: cd[start] = '0' else: cd[start] = '1' c = f f = HT[f].parent # 为第i个字符串编码分配空间 HC[i] = ''.join(cd[start:]) return HC ``` ### 应用优势 通过哈夫曼编码,频率高的字符数据编码长度变短,在处理大量字符时,会大大减少存储率和传输成本。例如原编码二进制串为“000001010011100101”,经过哈夫曼编码后变为“01100110100111000”[^3]。 ### 构建基础 构建哈夫曼哈夫曼编码的基础,根据字符的频率,使用自底向上的方法构建。在构建过程中,将频率最低的两个节点合并为一个新的节点,其频率为两者之和,并将这两个字符分别作为新节点的左右子节点。然后,将新节点加入到未处理的字符列表中,继续重复此过程,直到所有字符都被合并到一个根节点下[^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值