首页 快讯正文

晋城新闻综合频道:重学数据结构之哈夫曼树

admin 快讯 2020-05-19 8 0

一、哈夫曼树

1.带权扩充二叉树的外部路径长度

  扩充二叉树的外部路径长度,即根到其叶子节点的路径长度之和。

  例如下面这两种带权扩充二叉树:

  

  左边的二叉树的外部路径长度为:(2 + 3 + 6 + 9) * 2 = 38。

  右边的二叉树的外部路径长度为:9 + 6 * 2 + (2 + 3) * 3 = 36。

2.哈夫曼树

  哈夫曼树(Huffman Tree)是一种主要的二叉树,在信息领域有主要的理论和现实价值。

  设有实数集 W = {W0 ,W1 ,···,Wm-1 },T 是一颗扩充二叉树,其 m 个外部节点划分以 Wi (i = 1, 2, n - 1) 为权,而且 T 的带权外部路径长度在所有这样的扩充二叉树中到达最小,则称 T 为数据集 W 的最优二叉树或者哈夫曼树。

 

二、哈夫曼算法

1.基本概念

  哈夫曼(D.A.Huffman)提出了一个算法,它能从随便的实数聚集组织出与之对应的哈夫曼树。这个组织算法形貌如下:

  • 算法的输入为实数聚集 W = {W0 ,W1 ,···,Wm-1 }。
  • 在组织中维护一个包罗 k 个二叉树聚集的聚集 F,最先时k = m 且 F = {T0 ,T1 ,···,Tm-1 },其中每个 Ti 是一颗只包罗权为 Wi 的根节点的二叉树。

  该算法的组织历程中会重复执行以下两个步骤,直到聚集 F 中只剩下一棵树为止:

  1. 组织一颗二叉树,其左右子树是从聚集 F 中选取的两颗权值最小的二叉树,其根节点的权值设置为这两颗子树的根节点的权值之和。
  2. 将所选取的两颗二叉树从聚集 F 中删除,把新组织的二叉树加入到聚集 F 中。 

  注重:给定聚集 W 上的哈夫曼树并不唯一!

2.示例

  对于实数聚集 W = {2, 1, 3, 7, 8, 4, 5},下面的图1到图7示意了从这个实数聚集最先,组织一个哈夫曼树的历程:

  图1:

   图2:

 

   图3:

 

  图4:   

  图5: 

 

  图6: 

 

  图7: 

 

 

三、哈夫曼算法的实现

1.实现思绪

  要实现哈夫曼算法,需要维护一组二叉树,而且要知道每颗二叉树的根节点的权值 ,这个可以使用前面界说的二叉树的节点来组织哈夫曼树,只需要在根节点处纪录该树的权值。而在执行算法时

  在算法最先时,需要凭据传入的实数集和来建立一组单节点的二叉树,并以权值作为其优先级存入一个优先级行列之中,在之后的历程中频频执行以下两步,直至行列中只有一颗二叉树:

  1)从该优先级行列中取出两颗权值最小的二叉树;

  2)建立一颗新的二叉树,其权值为选出的两棵树的权值之和,其左右子树划分为选出的两颗树,并将建立好的二叉树加入到优先级行列中。

  当整个优先级行列中只剩下一颗二叉树的时刻,就获得我们需要的哈夫曼树了。

2.实现代码

  首先是要对哈夫曼树的节点举行界说,主要是增添一个权值,界说哈夫曼树节点的代码如下:

1 # 哈夫曼树节点
2 class HNode(Node):
3     def __init__(self, value=None, left=None, right=None, weight=None):
4         super(HNode, self).__init__()
5         self.value = value
6         self.left = left
7         self.right = right
8         self.weight = weight

  然后还需要一个优先级的行列,在我前面写过的一篇行列的博客中有提到,只不过那篇博客里的优先级行列用的是一个最大堆,而在这里需要用最小堆,这样每次才气取出权值最小的树。

  最后,下面就是实现哈夫曼算法的主要代码了:

 1 def create(weights: list):
 2     """
 3     凭据传入的权值列表建立一个哈夫曼树
 4     :param weights: 实数聚集
 5     """
 6     queue = PriorityQueue()
 7     # 将节点添加到优先级行列中
 8     for weight in weights:
 9         node = HNode(weight=weight)
10         queue.enqueue(node, weight)
11     while queue.size() > 1:
12         node1 = queue.dequeue()
13         node2 = queue.dequeue()
14         new_node = HNode(left=node1, right=node2, weight=node1.weight + node2.weight)
15         queue.enqueue(new_node, new_node.weight)
16     return queue.dequeue()

 

四、哈夫曼编码问题

1.问题形貌 

  最优编码问题,给定两个聚集 C 和 W,C 为基本数据聚集,W 为 C 中各个字符在现实信息通报中使用的频率,要求设定一套编码规则,要求: 1)使用这种编码规则的开销最小; 2)对随便一对差别字符 Ci 和 Cj,要求 Ci 的编码不是 Cj 编码的前缀。

2.问题剖析

  使用哈夫曼算法构建一颗哈夫曼树,这棵树的叶子节点的数目和字符数目一致,叶子节点的值就是字符的值,叶子节点的权值就是该字符对应的使用频率。然后从根节点最先遍历,往左子树遍历时符号为0,往右子树遍历时符号为1,这样就能保证走到叶子节点时所符号的路径效果是不一样的了,最后将每个叶子节点的值和对应的符号效果返回,就是问题所求的最优编码。

  例如输入的数据为:{"A": 2, "b": 3, "c": 5, "d": 6, "e": 9} 。

  则组织出来的哈夫曼树如下图:

  最后获得的编码为:{"A": "000", "b": "001", "c": "01", "d": "10", "e": "11"} 

3.代码实现

  下面就是使用哈夫曼算法来求解编码问题的主要代码了:

 1 from Tree.tree import Node
 2 from Queue.queue import PriorityQueue
 3 
 4 
 5 # 哈夫曼树节点
 6 class HNode(Node):
 7     def __init__(self, value=None, left=None, right=None, weight=None):
 8         super(HNode, self).__init__()
 9         self.value = value
10         self.left = left
11         self.right = right
12         self.weight = weight
13 
14 
15 # 自界说哈夫曼树
16 class HuffmanTree:
17     def __init__(self):
18         self.root = HNode()
19         self.code = {}
20 
21     def get_leaves(self, node: HNode, code: str):
22         """
23         获取所有叶节点,对树中的分支节点向左子节点的路径符号为0,向右子节点的路径符号为1
24         :param node: 哈夫曼树的节点
25         :param code: 字符使用的编码
26         :return:
27         """
28         if not node:
29             return
30         code_ = code  # 由于要划分向左向右探索路径,以是需要复制一份
31         if node.left:
32             code += "0"
33             self.get_leaves(node.left, code)
34         if node.right:
35             code_ += "1"
36             self.get_leaves(node.right, code_)
37         # 没有左右子节点,解释是叶子节点
38         if not node.left and not node.right:
39             self.code[node.value] = code
40 
41     def create(self, char_data: dict):
42         """
43         凭据传入的权值列表建立一个哈夫曼树
44         :param char_data: 字符和其对应频率的字典
45         """
46         queue = PriorityQueue()
47         # 将节点添加到优先级行列中
48         for char, weight in char_data.items():
49             node = HNode(value=char, weight=weight)
50             queue.enqueue(node, weight)
51         while queue.size() > 1:
52             node1 = queue.dequeue()
53             node2 = queue.dequeue()
54             new_node = HNode(left=node1, right=node2, weight=node1.weight + node2.weight)
55             queue.enqueue(new_node, new_node.weight)
56         self.root = queue.dequeue()
57 
58 
59 def solution(char_data: dict):
60     """
61     解决哈夫曼编码问题
62     :param char_data: 字符和其对应频率的字典
63     :return:
64     """
65     tree = HuffmanTree()
66     tree.create(char_data)
67     tree.get_leaves(tree.root, "")
68     return tree.code
,

Sunbet

Sunbet申博 www.sunbet88.us是Sunbet指定的Sunbet官网,Sunbet提供Sunbet(Sunbet)、Sunbet、申博代理合作等业务。

版权声明

本文仅代表作者观点,
不代表本站诚信在线的立场。
本文系作者授权发表,未经许可,不得转载。

好文推荐

站点信息

  • 文章总数:590
  • 页面总数:0
  • 分类总数:16
  • 标签总数:643
  • 评论总数:56
  • 浏览总数:35079