Python描述数据结构学习之哈夫曼树篇


Posted in Python onSeptember 07, 2020

前言

本篇章主要介绍哈夫曼树及哈夫曼编码,包括哈夫曼树的一些基本概念、构造、代码实现以及哈夫曼编码,并用Python实现。

1. 基本概念

哈夫曼树(Huffman(Huffman(Huffman Tree)Tree)Tree),又称为最优二叉树,指的是带权路径长度最小的二叉树。树的带权路径常记作:

Python描述数据结构学习之哈夫曼树篇

其中,nnn为树中叶子结点的数目,wkw_kwk​为第kkk个叶子结点的权值,lkl_klk​为第kkk个叶子结点与根结点的路径长度。

带权路径长度是带权结点和根结点之间的路径长度与该结点的权值的乘积。有关带权结点、路径长度的概念请参阅这篇博客。

对于含有nnn个叶子结点的哈夫曼树,其共有2n12n-12n−1个结点。因为在构造哈夫曼树的过程中,每次都是以两颗二叉树为子树创建一棵新的二叉树,因此哈夫曼树中不存在度为1的结点,即n1=0n_1=0n1​=0,由二叉树的性质可知,叶子结点数目n0=n2+1n_0=n_2+1n0​=n2​+1,所以n2=n01n_2=n_0-1n2​=n0​−1,总结点数目为n=n0+n1+n2=n+n1=2n1n=n_0+n_1+n_2=n+n-1=2n-1n=n0​+n1​+n2​=n+n−1=2n−1。

2. 构造过程及实现

给定nnn棵仅含根结点的二叉树T1,T2,,TnT_1,T_2,\dots,T_nT1​,T2​,…,Tn​,它们的权值分别为w1,w2,,wnw_1,w_2,\dots,w_nw1​,w2​,…,wn​,将它们放入到一个集合FFF中,即F={T1,T2,,Tn}F=\{T_1,T_2,\dots,T_n\}F={T1​,T2​,…,Tn​};然后在集合FFF中选取两棵权值最小的根结点构造一棵新的二叉树,使新二叉树的根结点的权值等于其左、右子树根结点的权值之和;再然后将选中的那两个结点从集合FFF中删除,将新的二叉树添加到FFF中;继续重复上述操作,直至集合FFF中只剩一棵二叉树为止。

比如F={(A,3),(B,7),(C,2),(D,11),(E,13),(F,15),(G,9)}F=\{(A,3),(B,7),(C,2),(D,11),(E,13),(F,15),(G,9)\}F={(A,3),(B,7),(C,2),(D,11),(E,13),(F,15),(G,9)},它构造出来的哈夫曼树就是下面这棵二叉树:

Python描述数据结构学习之哈夫曼树篇

代码实现:

class HuffmanTreeNode(object):
 def __init__(self):
 self.data = '#'
 self.weight = -1
 self.parent = None
 self.lchild = None
 self.rchild = None


class HuffmanTree(object):
 def __init__(self, data_list):
 self.nodes = []
 # 按权重从大到小进行排列
 for val in data_list:
  newnode = HuffmanTreeNode()
  newnode.data = val[0]
  newnode.weight = val[1]
  self.nodes.append(newnode)
 self.nodes = sorted(self.nodes, key=lambda node: node.weight, reverse=True)
 print([(node.data, node.weight) for node in self.nodes])

 def CreateHuffmanTree(self):
 # 这里注意区分
 # TreeNode = self.nodes[:] 变量TreeNode, 这个相当于深拷贝, TreeNode变化不影响nodes
 # TreeNode = self.nodes 指针TreeNode与nodes共享一个地址, 相当于浅拷贝, TreeNode变化会影响nodes
 TreeNode = self.nodes[:]
 if len(TreeNode) > 0:
  while len(TreeNode) > 1:
  letfTreeNode = TreeNode.pop()
  rightTreeNode = TreeNode.pop()
  newNode = HuffmanTreeNode()
  newNode.lchild = letfTreeNode
  newNode.rchild = rightTreeNode
  newNode.weight = letfTreeNode.weight + rightTreeNode.weight
  letfTreeNode.parent = newNode
  rightTreeNode.parent = newNode
  self.InsertTreeNode(TreeNode, newNode)
  return TreeNode[0]

 def InsertTreeNode(self, TreeNode, newNode):
 length = len(TreeNode)
 if length > 0:
  temp = length - 1
  while temp >= 0:
  if newNode.weight < TreeNode[temp].weight:
   TreeNode.insert(temp+1, newNode)
   return True
  temp -= 1
 TreeNode.insert(0, newNode)

3. 哈夫曼编码

在数据通信时,假如我们要发送ABCDEFG”“ABCDEFG”“ABCDEFG”这一串信息,我们并不会直接以这种形式进行发送,而是将其编码成计算机能够识别的二进制形式。根据编码类型可将其分为固定长度编码和可变长度编码,顾名思义,固定长度编码就是编码后的字符长度都相同,可变长度编码就是编码后的字符长度不相同。这两种类型有什么区别呢?我们来举例说明一下:

AA BB CC DD EE FF GG
固定长度编码 000000 001001 010010 011011 100100 101101 110110
可变长度编码 00 11 0101 1010 1111 101101 110110

ABCDEFG”“ABCDEFG”“ABCDEFG”这条信息使用固定长度编码后的长度为21,使用可变长度编码后的长度为14,报文变短,报文的传输效率会相应的提高。但如果传送的字符为BD”“BD”“BD”,按可变长度编码后的报文为111”“111”“111”,但是在译码是就会出现BBB,BD,DB”“BBB”,“BD”,“DB”“BBB”,“BD”,“DB”多种结果,因此采用可变长度编码时需要注意任一字符不能是其他字符的前缀,符合这样的可变长度编码称为前缀编码。

报文最短可以引申到二叉树路径最短,即构造前缀编码的实质就是构造一棵哈夫曼树,通过这种形式获得的二进制编码称为哈夫曼编码。这里的权值就是报文中字符出现的概率,出现概率越高的字符我们用越短的字符表示。

以下表中的字符及其出现的概率为例来实现哈夫曼编码:

字符 AA BB CC DD EE FF GG HH
出现概率 0.010.01 0.430.43 0.150.15 0.020.02 0.030.03 0.210.21 0.070.07 0.08
哈夫曼编码 101010101010 00 110110 101011101011 1010010100 111111 10111011 100

Python描述数据结构学习之哈夫曼树篇

代码实现就是在哈夫曼树的基础上加一个编码的函数:

def HuffmanEncode(self, Root):
  TreeNode = self.nodes[:]
  code_result = []
  for index in range(len(TreeNode)):
   temp = TreeNode[index]
   code_leaf = [temp.data]
   code = ''
   while temp is not Root:
    if temp.parent.lchild is temp:
     # 左分支
     code = '0' + code
    else:
     # 右分支
     code = '1' + code
    temp = temp.parent
   code_leaf.append(code)
   code_result.append(code_leaf)
  return code_result

测试结果如下:

if __name__ == '__main__':
 tree_obj = HuffmanTree([('A', 0.01), ('B', 0.43), ('C', 0.15), ('D', 0.02), ('E', 0.03), ('F', 0.21), ('G', 0.07), ('H', 0.08)])
 huf_tree = tree_obj.CreateHuffmanTree()
 huf_code = tree_obj.HuffmanEncode(huf_tree)
 for index in range(len(huf_code)):
  print('{0}: {1}'.format(huf_code[index][0], huf_code[index][1]))

Python描述数据结构学习之哈夫曼树篇

总结

到此这篇关于Python描述数据结构学习之哈夫曼树篇的文章就介绍到这了,更多相关Python数据结构之哈夫曼树内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python极简代码实现杨辉三角示例代码
Nov 15 Python
Python实现句子翻译功能
Nov 14 Python
Python运维开发之psutil库的使用详解
Oct 18 Python
对Python中list的倒序索引和切片实例讲解
Nov 15 Python
浅谈Python中的可迭代对象、迭代器、For循环工作机制、生成器
Mar 11 Python
python读取Excel表格文件的方法
Sep 02 Python
使用Python制作一个打字训练小工具
Oct 01 Python
用Python实现校园通知更新提醒功能
Nov 23 Python
Pandas实现dataframe和np.array的相互转换
Nov 30 Python
pytorch实现mnist数据集的图像可视化及保存
Jan 14 Python
Python3爬虫带上cookie的实例代码
Jul 28 Python
python调用百度API实现人脸识别
Nov 17 Python
python简单利用字典破解zip文件口令
Sep 07 #Python
python 如何快速复制序列
Sep 07 #Python
Python2与Python3关于字符串编码处理的差别总结
Sep 07 #Python
python 装饰器的实际作用有哪些
Sep 07 #Python
通俗讲解python 装饰器
Sep 07 #Python
彻底搞懂python 迭代器和生成器
Sep 07 #Python
python如何设置静态变量
Sep 07 #Python
You might like
php实现单链表的实例代码
2013/03/22 PHP
解析PHP中一些可能会被忽略的问题
2013/06/21 PHP
jquery 将disabled的元素置为enabled的三种方法
2009/07/25 Javascript
Javascript 键盘keyCode键码值表
2009/12/24 Javascript
JavaScript 注册事件代码
2011/01/27 Javascript
js使用函数绑定技术改变事件处理程序的作用域
2011/12/26 Javascript
js变换显示图片的实例
2013/04/16 Javascript
asp.net刷新本页面的六种方法总结
2014/01/07 Javascript
jQuery中:image选择器用法实例
2015/01/03 Javascript
js监听input输入框值的实时变化实例
2017/01/26 Javascript
JS基于面向对象实现的多个倒计时器功能示例
2017/02/28 Javascript
使用JS在浏览器中判断当前网络连接状态的几种方法
2017/05/05 Javascript
jQuery 实时保存页面动态添加的数据的示例
2017/08/14 jQuery
微信小程序支付功能 php后台对接完整代码分享
2018/06/12 Javascript
微信小程序实现滴滴导航tab切换效果
2018/07/24 Javascript
OpenLayers3实现鼠标移动显示坐标
2020/09/25 Javascript
python实现的简单RPG游戏流程实例
2015/06/28 Python
使用Turtle画正螺旋线的方法
2017/09/22 Python
Python 3实战爬虫之爬取京东图书的图片详解
2017/10/09 Python
Python自动化运维_文件内容差异对比分析
2017/12/13 Python
Django的HttpRequest和HttpResponse对象详解
2018/01/26 Python
对Python 窗体(tkinter)树状数据(Treeview)详解
2018/10/11 Python
Python数据可视化之画图
2019/01/15 Python
centos 安装Python3 及对应的pip教程详解
2019/06/28 Python
解决Python import docx出错DLL load failed的问题
2020/02/13 Python
python 实现图片裁剪小工具
2021/02/02 Python
关于.NET, HTML的五个问题
2012/08/29 面试题
后勤自我鉴定
2013/10/13 职场文书
超市中秋节促销方案
2014/03/21 职场文书
大班开学家长寄语
2014/04/04 职场文书
夫妻婚内购房协议书
2014/10/05 职场文书
领导个人查摆剖析材料
2014/10/29 职场文书
发布会邀请函
2015/01/31 职场文书
农业项目合作意向书
2015/05/08 职场文书
新手入门Mysql--sql执行过程
2021/06/20 MySQL
Python中递归以及递归遍历目录详解
2021/10/24 Python