快速理解哈夫曼树的构造与哈夫曼编码

目录

哈夫曼树的构造

哈夫曼编码


哈夫曼树通常以二叉树的形式出现,采用贪心算法的思想。

二叉树:每个节点仅有两个子节点,举个栗子,如下图:

不过这并不是哈夫曼树,这只是一棵平平无奇的二叉树。真正的哈夫曼树请听我娓娓道来。 


哈夫曼树的构造

若我们已知结点的权值的集合为(5,19,21,2,3,6,7,10,32,14,52),我们该如何构造他的哈夫曼树呢?

我们可以有如下步骤:

  1. 找到当前权值集合中最小的两个权值并将其相加,构成新的权值。
  2. 将新的权值放入集合中,重复第一步,直到所有的权值都已经使用过了。

那么对于上面我们提到的这个集合,按照我们的两步走策略我们不难得出以下解题思路:

PS:最终的效果图我会在讲解完思路后给出

  1. 首先找出两个最小的权值2和3,我们先画在草稿纸上,并将其相加,得出一个新的权值5,将5分别与2和3相连,同时将集合中的2和3用5替换,得到新的集合为(5,19,21,5,6,7,10,32,14,52)。
  2. 在新的集合(5,19,21,5,6,7,10,32,14)中,我们找出最小的两个权值是5和5(没错,不是我写重复了,就是这样),加入已经构造好的哈夫曼树,得到新的权值10并把两个5用10替换,得到(19,21,10,6,7,10,32,14,52)。注意,为了最终构造完成的哈夫曼树更加整洁规范,我们一般把小的数字写在左边,大的写在右边。
  3. 在(19,21,10,6,7,10,32,14,52)中找出最小的两个权值6和7,加入构造好的哈夫曼树,得到新的权值13并替换6和7。
  4. 在(19,21,10,13,10,32,14,52)中找出最小的两个权值10和10,加入哈夫曼树,得到新的权值20并替换两个10。
  5. 在(19,21,20,13,32,14,52)中找出最小的两个权值13和14,加入哈夫曼树,得到新的权值27并替换13和14。
  6. 在(19,21,20,27,32,52)中找出最小的两个权值19和20,加入哈夫曼树,得到新的权值39并替换19和20。
  7. 在(21,39,27,32,52)中找出最小的两个权值21和27,加入哈夫曼树,得到新的权值48并替换21和27。
  8. 在(39,48,32,52)中找出最小的两个权值39和32,加入哈夫曼树,得到新的权值71并替换39和32。
  9. 在(71,48,52)中找出最小的两个权值48和52,加入哈夫曼树,得到新的权值100并替换48和52。
  10. 此时我们终于来到最后一步,在(71,100)中找出最小的两个(然而就剩两个了)权值71和100,加入哈夫曼树,得到新的权值171,此时我们就只剩一个权值,完成树后即结束构造。

最终的效果图如下:

那么讲完哈夫曼树的构造,哈夫曼编码又是什么?


哈夫曼编码

 哈夫曼编码简单来讲可以用8个字来记忆:左零右一,按路查询。每个节点与左孩子的路径标为0,与右孩子的路径标为1,得出如下图:


那么此时如果我们要求结点6的哈夫曼编码,我们就从根结点171出发,一直朝着结点6的方向出发,这个过程有点像DFS一直走到底的“特性”,走到6后我们就会得出它的哈夫曼编码为10100。原理是从根结点171出发到结点6时,我们经过171-100,100-48,48-27,27-13,13-6共5条路径,这路条路径的“编码”分别为1,0,1,0,0,因此我们可以得到6的哈夫曼编码为10100。

同理如果我们要求结点32的哈夫曼编码,我们则可以从171出发,走到32,得出结点32的哈夫曼编码为00。其他的结点求解方法相同。

但是在实际做题中,一般一个结点会对应一个字母或其他物品,如下图,他们的原理一致。


在这题中,唯一有所区别的是我们在文章中讲的是权值,这题中用到的是频率,其实质一样,我们假设共有100个字符,那么每个字母出现的次数就为(7,19,2,6,32,3,21,10),这个集合一出现,是否又眼熟起来了?

今天对哈夫曼树及其编码的讲解就到这里,如果对您有所帮助,希望您可以为我留下一个点赞和关注,这对我真的很重要,谢谢!

  • 46
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是构造并根据哈构造编码的步骤和示例代码: 1. 统计每个字符出现的频率,并将它们存储在一个字典中。 2. 将每个字符及其频率作为一个节点,构造一个森林。 3. 从森林中选出两个频率最小的节点,将它们合并成一个新节点,并将新节点的频率设置为两个节点的频率之和。将新节点插入森林中。 4. 重复步骤3,直到森林中只剩下一个节点,这个节点就是哈的根节点。 5. 根据哈构造编码。从根节点开始,遍历哈,当遇到左子时,在编码的末尾添加0,当遇到右子时,在编码的末尾添加1。当遍历到叶子节点时,就得到了该字符的哈编码。 以下是示例代码: ```python # 定义节点类 class Node: def __init__(self, freq, char=None): self.freq = freq self.char = char self.left = None self.right = None # 统计字符频率 def count_freq(text): freq = {} for char in text: if char in freq: freq[char] += 1 else: freq[char] = 1 return freq # 构造 def build_huffman_tree(freq): forest = [Node(freq[char], char) for char in freq] while len(forest) > 1: forest.sort(key=lambda x: x.freq) node1 = forest.pop(0) node2 = forest.pop(0) new_node = Node(node1.freq + node2.freq) new_node.left = node1 new_node.right = node2 forest.append(new_node) return forest[0] # 构造编码 def build_huffman_code(node, code=''): if node.char: print(node.char, code) else: build_huffman_code(node.left, code + '0') build_huffman_code(node.right, code + '1') # 示例 text = 'hello world' freq = count_freq(text) tree = build_huffman_tree(freq) build_huffman_code(tree) ``` 输出结果为: ``` d 00 h 01 r 100 e 1010 w 1011 o 110 l 1110 1111 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值