当前位置: 首页 > article >正文

递归方法构建哈夫曼树

1 问题

在进行数据压缩时,哈夫曼编码经常被用来进行无损压缩。哈夫曼编码是一种可变长度编码,通过将出现频率高的字符用较短的编码表示,从而减少压缩后的数据大小。而哈夫曼树就是用来生成哈夫曼编码的数据结构。

通常哈夫曼树的构建通过使用最小堆实现,但是我们也可以使用递归方法来构建哈夫曼树。那么问题来了:如何使用递归方法构建哈夫曼树?并打印出每个字符对应的哈夫曼编码。

2 方法

使用递归方法构建哈夫曼树的基本思想是:每次从权值最小的两个节点构建出一个新的父节点,然后将这个父节点插入到节点集合中,再将这个集合中权值最小的两个节点删除。重复这个过程直到只剩下一个节点。

具体步骤如下:

  1. 定义节点类 Node,它包含三个属性:

    左子节点 left、右子节点 right 和权值 weight。

  2. 编写一个递归函数用来构建哈夫曼树。

    该函数的输入是节点集合 nodes,输出是根节点 root。

    算法的基本思路:

    如果节点集合 nodes 的长度为 1,那么它就是哈夫曼树的根节点,直接返回。

    否则,从节点集合中找到权值最小的两个节点,分别记为 small_node 和 big_node,将它们的权值相加得到新节点的权值。

    创建一个新节点 parent_node,它的左子节点为 small_node,右子节点为 big_node,权值为它们的权值之和。

    从节点集合中删除 small_node 和 big_node,并将 parent_node 加入节点集合。

    递归调用函数,传入新的节点集合 nodes,直到节点集合的长度为 1

  3. 构建哈夫曼编码,即将每个字符对应的编码进行打印。

    这里我们需要编写另一个递归函数 build_huffman_code_table,该函数用来构建哈夫曼编码表。

    具体来说,该函数的输入是根节点 root,输出是一个字典,其中键为每个字符的权值,值为对应的哈夫曼编码。

通过实验、实践等证明提出的方法是有效的,是能够解决开头提出的问题。

代码清单 1

# 首先我们需要定义节点类 Node,它包含三个属性:左子节点 left、右子节点 right 和权值 weight
class Node:
   def __init__(self, left=None, right=None, weight=0):
       self.left = left
       self.right = right
       self.weight = weight
# 递归函数用来构建哈夫曼树
def build_huffman_tree(nodes):
   if len(nodes) == 1:
       return nodes[0]
   # 找到权值最小的两个节点
   small_node = min(nodes, key=lambda x: x.weight)
   nodes.remove(small_node)
   big_node = min(nodes, key=lambda x: x.weight)
   nodes.remove(big_node)
   # 创建新节点
   parent_node = Node(left=small_node, right=big_node, weight=small_node.weight+big_node.weight)
   nodes.append(parent_node)
   # 递归调用函数
   return build_huffman_tree(nodes)
# 构建哈夫曼编码
def build_huffman_code_table(root):
   def build_code_table_helper(node, code=''):
       if node is None:
           return {}
       if node.left is None and node.right is None:
           return {node.weight: code}
       return {**build_code_table_helper(node.left, code+'0'), **build_code_table_helper(node.right, code+'1')}
   return build_code_table_helper(root)
# 构建测试数据
data = [('A', 5), ('B', 7), ('C', 10), ('D', 15), ('E', 20), ('F', 25)]
nodes = [Node(weight=w) for _, w in data]
# 构建哈夫曼树
root = build_huffman_tree(nodes)
# 打印哈夫曼编码
code_table = build_huffman_code_table(root)
for char, weight in data:
   print(f'字符 {char}: 哈夫曼编码 {code_table[weight]}')
'''
输出结果:
字符 A: 哈夫曼编码 1010
字符 B: 哈夫曼编码 1011
字符 C: 哈夫曼编码 100
字符 D: 哈夫曼编码 00
字符 E: 哈夫曼编码 01
字符 F: 哈夫曼编码 11
'''

3 结语

通过实验发现,使用递归方法构建哈夫曼树是有效的。哈夫曼树通过将出现频率高的字符用较短的编码表示,从而减少压缩后的数据大小。它的构建基于贪心算法,可以使用最小堆实现,也可以使用递归方法构建。当然,使用递归方法构建哈夫曼树并不是最优解,但它能够帮助我们更好地理解哈夫曼编码的本质。


http://www.kler.cn/a/273564.html

相关文章:

  • Spring Boot 配置文件启动加载顺序
  • 人工智能原理实验一:知识的表示与推理实验
  • 防重方案-订单防重方案笔记
  • c怎么与python交互
  • 基于STM32+华为云IOT设计的大棚育苗管理系统
  • Java毕业设计-基于微信小程序的校园二手物品交易系统的实现(V2.0)
  • C语言calloc函数的特点,效率低。但是进行初始化操作
  • V-JEPA模型,非LLM另外的选择,AGI的未来:迈向Yann LeCun先进机器智能(AMI)愿景的下一步
  • IPC之管道
  • Android14之HIDL报错:Invalid sparse file format at header magic(一百九十六)
  • RHCE——三:Web服务器(内网穿透实验)
  • transferto转换文件类型报错
  • Auto-DataProcessing:一组让制作数据集变轻松的脚本
  • 显示android设备所以已安装App 可点击启动、搜索
  • Halcon 点云处理流程(点云分割、连通筛选、模型位姿变换、三角化)
  • Linux命令-dhclient命令(动态获取或释放IP地址)
  • 前后端分离项目部署服务器教程--实践成功
  • 【简历篇】如何写简历(二)简历元素、技巧、规范、三省
  • Git——GitHub远端协作详解
  • Apache Doris 如何基于自增列满足高效字典编码等典型场景需求
  • 在Hive中使用Python编写的UDF函数
  • 全量知识系统 微服务及特征复数空间和立体逻辑方阵的设想及百度AI回复
  • MySql安装与卸载—我耀学IT
  • 小程序云开发(十六):JavaScript基础
  • 浅谈Java 编程语言
  • 全量知识系统“全基因序列”程序构想及SmartChat的回复