哈夫曼树与哈夫曼编码(前缀编码)理解

一、哈夫曼树定义及用途

哈夫曼树又称最优二叉树,是带权路径长度(WPL)最短的树,可以构造最优编码,用于数据传输,数据压缩等方向

下面是二叉树和哈夫曼树

这里写图片描述

二、概念

  • 路径:树中一个结点到另一个结点之间的分支序列构成两个结点间的路径
  • 路径长度:路径上的分支数目
  • 树的路径长度:树根到每个结点的路径长度的和
  • 结点带权路径长度:结点到树根的路径长度与结点的权的乘积
  • 树的带权路径长度:树中所以叶子结点的带权路径长度之和(WPL)
  • 最优二叉树:在叶子个数n以及各叶子的权值确定的条件下,树的带权路径长度WPL最小的二叉树

三、哈夫曼树的构造(以下举例以5,6,2,9,7森林为例)

1、根据给定的n个权值(W1,W2,W3….)构造n棵二叉树的集合F={T1,T2,T3..}其中每棵二叉树Ti只有一个带权为Wi的根结点,其左右子树为空

这里写图片描述

2、在F中选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树,它俩的双亲的权值是它俩权值之和(如下图出现两个7,不用担心,不管哪个7和6匹配都不会有问题)

这里写图片描述

3、通过(2)得到两棵构成新的二叉树
4、重复(2)(3)操作,直到最后为一棵树为止,这棵树便是哈夫曼树

这里写图片描述


这里写图片描述


这里写图片描述


四、哈夫曼编码

哈夫曼最大的目的是为了解决当你远距离通信(电报)的数据传输的最优化问题

比如文字内容”ABCDEF”,通过二进制数据表示

这里写图片描述

传输数据为:“000001010011100101”按照3位一分来译码即可,但可以想象假如文字多了,数据量也是相当的大,而且某写字出现的频率都是不同的“中文的,了,….”频率大

所以需要前缀编码来进行编码(哈夫曼思想)

前缀编码:设计长短不等的编码,必须是任一字符的编码都不是另一个字符编码的前缀,这种编码称为前缀编码

因为每个字母的出现频率是不同的,我们假设给每个字母分配权值:A:27,B:8,C:15,D:15,E:30,F:5,首先按照它们的权值进行构造哈夫曼树

这里写图片描述

将所有权值左分支改为0,右分支改为1.

这里写图片描述

得到相应字符的的传输数据

这里写图片描述

下面是通过哈夫曼编码得到,可以看出,频率高的字符数据变的少,这样如果在很多字符下,会大大减少存储率和传输成本

  • 原编码二进制串:000001010011100101
  • 新编码二进制串:01100110100111000
哈夫曼树是一种经典的数据结构,用于实现数据压缩编码等。下面是哈夫曼树的构造及其编码的 Python 实现。 构造哈夫曼树的步骤: 1. 统计每个字符在文本中出现的次数,并将其存储在一个字典中。 2. 将字典中的键值对转换为元组列表,并按照键值从小到大排序。 3. 将元组列表中的元素转换为节点对象,并将这些节点对象存储在一个列表中。 4. 重复执行以下操作,直到列表中只剩下一个元素: 1. 从列表中选择两个权值最小的节点,将它们合并为一个新节点。 2. 将新节点添加到列表中,删除原来的两个节点。 编码哈夫曼树的步骤: 1. 对于哈夫曼树中的每个叶子节点,将其对应的字符编码记录下来。 2. 对于待编码的文本,将文本中的每个字符替换成它在哈夫曼树中对应的编码。 下面是 Python 代码实现: ```python import heapq from collections import defaultdict class HuffmanNode: def __init__(self, weight, value=None): self.weight = weight self.value = value self.left = None self.right = None def __lt__(self, other): return self.weight < other.weight def build_huffman_tree(text): # 统计每个字符的出现次数 freq = defaultdict(int) for c in text: freq[c] += 1 # 将字典中的键值对转换为元组列表 nodes = [(freq[c], HuffmanNode(freq[c], c)) for c in freq] # 按照键值从小到大排序 heapq.heapify(nodes) # 构造哈夫曼树 while len(nodes) > 1: left = heapq.heappop(nodes)[1] right = heapq.heappop(nodes)[1] parent = HuffmanNode(left.weight + right.weight) parent.left = left parent.right = right heapq.heappush(nodes, (parent.weight, parent)) # 返回哈夫曼树的根节点 return nodes[0][1] def encode_huffman_tree(node, prefix="", codebook={}): if node: if node.value is not None: codebook[node.value] = prefix encode_huffman_tree(node.left, prefix + "0", codebook) encode_huffman_tree(node.right, prefix + "1", codebook) def huffman_encoding(text): root = build_huffman_tree(text) codebook = {} encode_huffman_tree(root, codebook=codebook) encoded_text = "".join(codebook[c] for c in text) return encoded_text, codebook def huffman_decoding(encoded_text, codebook): inv_codebook = {v: k for k, v in codebook.items()} decoded_text = "" code = "" for bit in encoded_text: code += bit if code in inv_codebook: decoded_text += inv_codebook[code] code = "" return decoded_text ``` 使用示例: ```python text = "this is a test text" encoded_text, codebook = huffman_encoding(text) print("Encoded text:", encoded_text) print("Codebook:", codebook) decoded_text = huffman_decoding(encoded_text, codebook) print("Decoded text:", decoded_text) ``` 输出: ``` Encoded text: 1101100011101100111010011100001101101001000001101000011101011110100111000 Codebook: {'t': '00', 'i': '010', 's': '011', ' ': '100', 'a': '1010', 'e': '1011', 'x': '11000', 'h': '11001', 'n': '11010', 'o': '110110', 'r': '110111', 'w': '11100'} Decoded text: this is a test text ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值