带你认识哈夫曼树


树的4个概念

  1. 什么是路径?

在一棵树中,从一个结点到另一个结点所经过的所有结点,被我们称为两个结点之间的路径。

在这里插入图片描述

上面的二叉树当中,从根结点A到叶子结点H的路径,就是A,B,D,H。

  1. 什么是路径长度?

在一棵树中,从一个结点到另一个结点所经过的“边”的数量,被我们称为两个结点之间的路径长度。

在这里插入图片描述

仍然用刚才的二叉树举例子,从根结点A到叶子结点H,共经过了3条边,因此路径长度是3。

  1. 什么是结点的带权路径长度?

树的每一个结点,都可以拥有自己的“权重”(Weight),权重在不同的算法当中可以起到不同的作用。
结点的带权路径长度,是指树的根结点到该结点的路径长度,和该结点权重的乘积。

在这里插入图片描述

假设结点H的权重是3,从根结点到结点H的路径长度也是3,因此结点H的带权路径长度是 3 X 3 = 9。

  1. 什么是树的带权路径长度?

在一棵树中,所有叶子结点的带权路径长度之和,被称为树的带权路径长度,也被简称为WPL。

在这里插入图片描述

仍然以这颗二叉树为例,树的路径长度是 3X3 + 6X3 + 1X2 + 4X2 + 8X2 = 53。

哈夫曼树概念

哈夫曼树是由麻省理工学院的哈夫曼博士于1952年发明,这到底是一颗什么样的树呢?

刚才我们学习了树的带权路径长度(WPL),而哈夫曼树(Huffman Tree)是在叶子结点和权重确定的情况下,带权路径长度最小的二叉树,也被称为最优二叉树。

举个例子,给定权重分别为1,3,4,6,8的叶子结点,我们应当构建怎样的二叉树,才能保证其带权路径长度最小?

原则上,我们应该让权重小的叶子结点远离树根,权重大的叶子结点靠近树根。

下图左侧的这棵树就是一颗哈夫曼树,它的WPL是46,小于之前例子当中的53:
在这里插入图片描述

需要注意的是,同样叶子结点所构成的哈夫曼树可能不止一颗,下面这几棵树都是哈夫曼树:

在这里插入图片描述

构建一个哈夫曼树

假设有6个叶子结点,权重依次是2,3,7,9,18,25,如何构建一颗哈夫曼树,也就是带权路径长度最小的树呢?

在这里插入图片描述

第一步:构建森林

我们把每一个叶子结点,都当做树一颗独立的树(只有根结点的树),这样就形成了一个森林:

在这里插入图片描述

在上图当中,右侧是叶子结点的森林,左侧是一个辅助队列,按照权值从小到大存储了所有叶子结点。至于辅助队列的作用,我们后续将会看到。

第二步:选择当前权值最小的两个结点,生成新的父结点

借助辅助队列,我们可以找到权值最小的结点2和3,并根据这两个结点生成一个新的父结点,父节点的权值是这两个结点权值之和:

在这里插入图片描述

第三步:从队列中移除上一步选择的两个最小结点,把新的父节点加入队列
也就是从队列中删除2和3,插入5,并且仍然保持队列的升序:

在这里插入图片描述

第四步:选择当前权值最小的两个结点,生成新的父结点。

这是对第二步的重复操作。当前队列中权值最小的结点是5和7,生成新的父结点权值是5+7=12:

在这里插入图片描述

第五步:从队列中移除上一步选择的两个最小结点,把新的父节点加入队列。

这是对第三步的重复操作,也就是从队列中删除5和7,插入12,并且仍然保持队列的升序:

在这里插入图片描述

第六步:选择当前权值最小的两个结点,生成新的父结点。

这是对第二步的重复操作。当前队列中权值最小的结点是9和12,生成新的父结点权值是9+12=21:

在这里插入图片描述

第七步:从队列中移除上一步选择的两个最小结点,把新的父节点加入队列。

这是对第三步的重复操作,也就是从队列中删除9和12,插入21,并且仍然保持队列的升序:

在这里插入图片描述

第八步:选择当前权值最小的两个结点,生成新的父结点。

这是对第二步的重复操作。当前队列中权值最小的结点是18和21,生成新的父结点权值是18+21=39:

在这里插入图片描述

第九步:从队列中移除上一步选择的两个最小结点,把新的父节点加入队列。

这是对第三步的重复操作,也就是从队列中删除18和21,插入39,并且仍然保持队列的升序:

在这里插入图片描述

第十步:选择当前权值最小的两个结点,生成新的父结点。

这是对第二步的重复操作。当前队列中权值最小的结点是25和39,生成新的父结点权值是25+39=64:

在这里插入图片描述

第十一步:从队列中移除上一步选择的两个最小结点,把新的父节点加入队列

这是对第三步的重复操作,也就是从队列中删除25和39,插入64:

在这里插入图片描述

此时,队列中仅有一个结点,说明整个森林已经合并成了一颗树,而这棵树就是我们想要的哈夫曼树:

在这里插入图片描述

知识点习题

  1. 有权值分别为11,8,6,2,5的叶子结点生成一棵哈夫曼树,它的带权路径长度为_______。

A. 24
B. 71
C. 48
D. 53

正确答案: B

答案解析:

  1. 画出哈夫曼树

(11 + 8 + 6)* 2 + (2 + 5) * 3 = 50 + 21 = 71

	   32
  13       19
6    7   8    11
   2  5
  1. 教大家一个快速解题的方法。特点:不需要画出哈夫曼树就能直接出答案

首先:将权值从小到大排序,然后像下图一样,每次合并的两个节点下面画一个横线,(期间可能要适当的调整结点)

在这里插入图片描述

权值的话,就等于所有的结点权值*横线个数之和。

  1. 给出下述节点及权值(括号中数字为权值),构造huffman树,其带权路径长度为() a(7),b(5),c(4),d(2)

A. 18
B. 35
C. 36
D. 46

正确答案: B

答案解析:

(2 + 4)3 + 52 + 7*1 = 35

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
哈夫曼树(Huffman Tree)是一种特殊的二叉树,用于数据压缩和编码。它的构建过程是根据字符出现的频率来确定每个字符的编码,使得出现频率高的字符具有较短的编码,而出现频率低的字符具有较长的编码。 以下是一个Python实现的哈夫曼树的例子: ```python class TreeNode: def __init__(self, value, freq): self.value = value self.freq = freq self.left = None self.right = None def build_huffman_tree(char_freq): nodes = [TreeNode(char, freq) for char, freq in char_freq.items()] while len(nodes) > 1: nodes = sorted(nodes, key=lambda x: x.freq) left_node = nodes.pop(0) right_node = nodes.pop(0) parent_node = TreeNode(None, left_node.freq + right_node.freq) parent_node.left = left_node parent_node.right = right_node nodes.append(parent_node) return nodes[0] def encode_huffman_tree(root, code='', codes={}): if root is None: return if root.value is not None: codes[root.value] = code encode_huffman_tree(root.left, code + '0', codes) encode_huffman_tree(root.right, code + '1', codes) return codes def decode_huffman_tree(root, encoded_text): decoded_text = '' current_node = root for bit in encoded_text: if bit == '0': current_node = current_node.left else: current_node = current_node.right if current_node.value is not None: decoded_text += current_node.value current_node = root return decoded_text # 示例用法 char_freq = {'a': 5, 'b': 9, 'c': 12, 'd': 13, 'e': 16, 'f': 45} huffman_tree = build_huffman_tree(char_freq) huffman_codes = encode_huffman_tree(huffman_tree) encoded_text = ''.join([huffman_codes[char] for char in 'abcdef']) decoded_text = decode_huffman_tree(huffman_tree, encoded_text) print("Huffman Codes:", huffman_codes) print("Encoded Text:", encoded_text) print("Decoded Text:", decoded_text) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值