Python完成哈夫曼树编码过程及原理详解
简介
哈夫曼编码(Huffman Coding)又称霍夫曼编码,是一种数据压缩方法。它是由David A. Huffman于1952年提出的一种编码方法,广泛应用于无损压缩领域。哈夫曼编码是一种前缀编码的变长编码方法,即每个字符的编码不是固定的比特串,而是由可变的比特串组成。它利用字符出现的概率来构建一棵特定的二叉树,将每个字符编码为该二叉树中从根到该字符所在叶子节点的路径上的左右节点字符。哈夫曼编码的主要原理是将出现频率高的字符用短编码表示,出现频率低的字符用长编码表示,以此来降低总体的编码长度。
编码过程
步骤1:统计字符出现频率
首先,我们需要统计要编码的字符串中各个字符出现的频率。具体方法是使用Python中的collections
模块中的Counter
类来实现:
from collections import Counter
text = "hello, world!"
freq = Counter(text)
步骤2:构建哈夫曼树
接下来,我们需要根据字符出现的频率构建哈夫曼树。首先,我们将每个字符及其频率封装为一个节点对象,并将这些节点对象添加到一个节点列表中。然后,对这个节点列表进行排序,按照从小到大的顺序依次选取两个频率最小的节点,将它们作为左右子节点构建一个新的父节点,并将这个新的父节点加入到节点列表中,直到剩下一个节点为止,这个节点就是哈夫曼树的根节点。具体的实现代码如下:
class Node:
def __init__(self, value, freq, parent=None, left_child=None, right_child=None):
self.value = value # 字符值
self.freq = freq # 字符出现的频率
self.parent = parent # 父节点
self.left_child = left_child # 左子节点
self.right_child = right_child # 右子节点
def is_leaf(self):
return not (self.left_child or self.right_child)
class HuffmanTree:
def __init__(self, freq):
nodes = [Node(value=char, freq=freq[char]) for char in freq] # 将字符及其频率封装为节点对象
while len(nodes) > 1:
nodes.sort(key=lambda x: x.freq) # 对节点进行排序
left_child = nodes.pop(0) # 取出频率最小的节点作为左子节点
right_child = nodes.pop(0) # 取出频率次小的节点作为右子节点
parent = Node(value=None, freq=left_child.freq + right_child.freq, left_child=left_child,
right_child=right_child) # 构建一个新的父节点
left_child.parent = parent # 将父节点作为左子节点的父节点
right_child.parent = parent # 将父节点作为右子节点的父节点
nodes.append(parent) # 将新的父节点加入到节点列表中
self.root = nodes[0] # 节点列表中剩下的一个节点就是哈夫曼树的根节点
步骤3:生成编码表
生成编码表的方法是利用哈夫曼树中从根到叶子节点的路径上的左右节点字符对应的编码值构成的编码表。具体方法是先从根节点出发,如果往左走就将这个字符的编码设为0,如果往右走就将这个字符的编码设为1。当到达叶子节点时,将这个字符对应的编码存储到编码表中。具体的实现代码如下:
def build_code_table(tree):
code_table = {}
for char in freq:
node = tree.get_node(char) # 获取节点对象
code = ''
while node.parent is not None:
if node.parent.left_child == node:
code = '0' + code # 往左走,将字符的编码设为0
else:
code = '1' + code # 往右走,将字符的编码设为1
node = node.parent # 继续向上走
code_table[char] = code
return code_table
步骤4:对原字符串进行编码
对原字符串进行编码的方法是将字符串中的每个字符依次查找编码表,并将它对应的编码值拼接起来即可。具体的实现代码如下:
def encode(text, code_table):
encoded_text = ''
for char in text:
encoded_text += code_table[char]
return encoded_text
示例1:对一个短字符串进行编码和解码
以下是一个简短的字符串“hello”的编码和解码示例:
# 统计字符出现的频率
freq = Counter('hello')
# 构建哈夫曼树
huffman_tree = HuffmanTree(freq)
# 生成编码表
code_table = build_code_table(huffman_tree)
# 对字符串进行编码
encoded_text = encode('hello', code_table)
print('Encoded Text:', encoded_text)
# 对编码后的字符串进行解码
decoded_text = decode(encoded_text, huffman_tree)
print('Decoded Text:', decoded_text)
输出结果为:
Encoded Text: 1110010100
Decoded Text: hello
示例2:对一个文本文件进行压缩和解压缩
以下是一个文本文件进行压缩和解压缩的示例:
# 统计字符出现的频率
counter = Counter()
with open('input.txt', 'r') as f:
for line in f:
counter.update(line.strip())
# 构建哈夫曼树
huffman_tree = HuffmanTree(counter)
# 生成编码表
code_table = build_code_table(huffman_tree)
# 对文件进行压缩
with open('compressed.bin', 'wb') as f:
with open('input.txt', 'r') as file:
for line in file:
encoded_line = encode(line.strip(), code_table)
f.write(int(encoded_line, 2).to_bytes((len(encoded_line) + 7) // 8, 'big'))
# 对压缩后的文件进行解压缩
with open('compressed.bin', 'rb') as f:
compressed_data = f.read()
decoded_data = decode_bin(compressed_data, huffman_tree)
with open('output.txt', 'w') as f:
f.write(decoded_data)
总结
哈夫曼编码是一种经典的数据压缩方法,它可以将某些数据以更小的体积存储和传输,从而达到节省空间、提高效率的目的。Python语言提供了丰富的标准库和第三方库,简单的代码就可以实现哈夫曼编码算法,是一种非常实用的工具。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python完成哈夫曼树编码过程及原理详解 - Python技术站