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

【数据结构】哈夫曼树和哈夫曼编码

一、哈夫曼树

1.1 哈夫曼树的概念

给定一个序列,将序列中的所有元素作为叶子节点构建一棵二叉树,并使这棵树的带权路径长度最小,那么我们就得到了一棵哈夫曼树(又称最优二叉树)

接下来是名词解释:

  • 权:节点的数值
  • 路径长度:两节点间路径的边数
  • 带权路径长度:节点的权值乘以该节点到根节点的路径长度即为该节点的带权路径长度。哈夫曼树的带权路径长度是树中所有叶子节点的带权路径长度之和。

例如下面这棵哈夫曼树:

通过观察我们可以发现,所有父节点的权值都是自身的两个子节点的权值之和。而为了要使树的带权路径长度最小,我们要尽可能的让权值小的节点离根节点远,让权值大的节点离根节点近

因此,我们引出哈夫曼树的构造算法。

1.2 哈夫曼树的构造算法

要将一个序列构造成一棵哈夫曼树,我们首先需要对其进行升序排序

将排序好后的序列中的每个值看作一棵只有一个节点的树,从中选出根节点权值最小的两棵树作为新树的左右子树,并将这两棵树从序列中删除,而新树的根节点的权值是这两棵树根节点的权值之和

哈夫曼树没有规定左右子树的顺序,因此下面的例子中将10和18的位置对调也是正确的

将新树的根节点的权值放入序列中并重新进行升序排序,重复上述步骤

至此,就构建了一棵哈夫曼树

因为哈夫曼树没有规定左右子树的顺序,因此一个序列可以构建出不同的哈夫曼树

二、哈夫曼编码

2.1 等长编码

假设我们要对一个字符串ABAACDC进行二进制编码

我们可以按顺序给每个字符设置一个编码,A为0,B为1,C为10,D为11

那么就可以将上面的字符串转化为0100101110

但是在解码的时候我们会发现,这一串二进制序列可以解码为ACACDBA、ACABABDA等字符串,出现了歧义。

这是因为我们在对字符进行编码的时候,出现了一个字符是另一个字符的前缀的情况,例如D可以用两个B来表示。

为了避免歧义,我们可以采用等长编码的方案,就是每个字符的编码都一样长,例如A为00,B为01,C为10,D为11,这样就不会产生歧义了。

但是这种方案并不是一个最短的方案。

2.2 哈夫曼编码

统计字符出现的次数,把字符定义成一个节点,节点的权值就是它出现的次数。

例如上面A出现了3次,B出现了1次,C出现了2次,D出现了1次

哈夫曼编码的核心思想就是让出现次数越多的字符编出来的码越短,我们将全部节点构建成一棵哈夫曼树,出现次数越少的字符对应的节点就越靠近树的底层,编码也就越长,出现次数越多的字符编码就越短。

对二叉树的边标号,向左的边标为0,向右的边标为1,至此所有字符的编码就是从根节点到该字符节点路径上经过的标号,例如A为1,B为010,C为00,D为011,这种编码方案就叫做哈夫曼编码。

构建哈夫曼树的时候,所有的字符节点都是叶子节点,不会出现一个字符出现在另一个字符的路径上,也就不会出现一个字符是另一个字符的前缀这种造成歧义的情况

哈夫曼树的编码不是唯一的,节点放置的左右也会造成字符编码的不同,但是生成的编码长度一定都是一样的。

完.

相关文章:

  • 全网最全爬取-b站爬取弹幕+评论之js逆向与xml降本增效
  • lua函数执行和虚拟机指令
  • UWB论文:Introduction to Impulse Radio UWB Seamless Access Systems(2):脉冲;超宽带;测距;定位
  • Flutter 中的 CupertinoPicker 小部件:全面指南
  • 【MySQL精通之路】SQL优化(1)-查询优化(11)-多范围查询优化
  • 开源RAG,本地mac启动 dify源码服务
  • 2024年第十七届“认证杯”数学中国数学建模网络挑战赛D题思路(第二阶段)
  • 解锁Nginx跨域谜题:3步打造安全高效的CORS策略
  • 【Centos7+JDK1.8】Jenkins安装手册
  • MySql:多表设计-关联查询
  • slam14讲(第8讲、前端里程计)LK光流、直接法
  • 【pyspark速成专家】3_Spark之RDD编程1
  • 【数据结构】第七节:堆
  • 鸿蒙开发配置官方地图
  • Python语法学习之 - 生成器表达式(Generator Expression)
  • [笔记] php常见简单功能及函数
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • GitUp, 你不可错过的秀外慧中的git工具
  • java概述
  • Joomla 2.x, 3.x useful code cheatsheet
  • js中forEach回调同异步问题
  • node和express搭建代理服务器(源码)
  • Python 反序列化安全问题(二)
  • Python_OOP
  • SSH 免密登录
  • 从输入URL到页面加载发生了什么
  • 高度不固定时垂直居中
  • 给第三方使用接口的 URL 签名实现
  • 简单数学运算程序(不定期更新)
  • 聚类分析——Kmeans
  • 那些被忽略的 JavaScript 数组方法细节
  • 实现简单的正则表达式引擎
  • 最简单的无缝轮播
  • 从如何停掉 Promise 链说起
  • ​如何使用QGIS制作三维建筑
  • #### golang中【堆】的使用及底层 ####
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • (13)Hive调优——动态分区导致的小文件问题
  • (C语言)球球大作战
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (贪心) LeetCode 45. 跳跃游戏 II
  • (一)项目实践-利用Appdesigner制作目标跟踪仿真软件
  • (自适应手机端)响应式服装服饰外贸企业网站模板
  • **PHP二维数组遍历时同时赋值
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • ./configure,make,make install的作用(转)
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .NET COER+CONSUL微服务项目在CENTOS环境下的部署实践
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .net dataexcel 脚本公式 函数源码
  • .NET delegate 委托 、 Event 事件,接口回调
  • .NET gRPC 和RESTful简单对比
  • .NET/C#⾯试题汇总系列:⾯向对象
  • .net生成的类,跨工程调用显示注释