哈夫曼树与哈夫曼编码

news2025/2/28 15:30:30

哈夫曼树:结点中赋予一个某种意义的值,称为结点的权值,从根结点开始,到目标结点经过的边数,称为路径长度,路径长度乘以权值,称为带权路径长度;

例如:根结点代表着快递集散点,一个叶子结点权值是5,在业务逻辑中代表着重量是5斤的货物📦,路径长度是3,业务逻辑代表着3公里,3 * 5 = 15 假设代表着从根结点开始配送这一件货物的成本 开销是15升汽油

越重的物品,配送距离越长,开销越大,假设说每一层结点都有一个快递柜,只可以存放一件物品,这样就让收件人自己来取,而不用大老远送过去了,那么我们就应该优先把最重的物品,放在距离快递集散点(根结点)越近的位置。重量轻的(权值小的)小件物品我们可以送远一点。
那么这个想法其实就是最短带权路径

例:假设快递站今天收到了6件需要派送的物品,重量(斤)分别是 6,9,1,3,2,12
如果快递员不懂巧妙利用最短带权路径,而是经过一个快递柜就按顺序把一件放进柜子,剩下的继续配送,那么构成的树就会是:
在这里插入图片描述
可以看到总耗费汽油109升。

但是转念一想,既然都可以放菜鸟柜,我为什么不把重的提前放下车,省点汽油呢?于是第二天快递员就改变思路,形成下面的二叉树:
在这里插入图片描述
果然,第二天只消耗了75升汽油,成本大大节约了

总结:综上所述,使得带权路径WPL最小的树,就称之为哈夫曼树。也可以称之为:最优二叉树

例子:

牢记哈夫曼树只有叶子结点能存放字符;同时哈夫曼树仅有度为0或者度为2的结点(因为是两两组合,不存在度为1)

(1)一棵哈夫曼树共有215个结点,对其进行哈夫曼编码,共能得到(108)个不同的码字
因为哈夫曼树只有叶子结点能存放码字
根据二叉树的性质,最后一个非叶结点是:215 / 2 向下取整 = 107
所以叶子结点就是:215 - 107 = 108
所以,能存放108个不同的码字

(2)【2019】对n个互不相同的符号进行哈夫曼编码,若生成的哈夫曼树共有115个结点,则n的值是()
结点总数为115,则最后一个非叶结点是:115 / 2 向下取整 = 57
则叶子结点是:115 - 57 = 58
所以能存放58个不同的符号

如何生成哈夫曼树?

在上面的例子我们从根往下生成,其实步骤是不对的,只是为了举例子,更容易的找出N个结点的最小带权路径的哈夫曼树的过程应该如下:
首先把N个结点看作N棵只有一个结点的树
(1)从N个结点中找出两个最小权值的树,组成一棵新树最底端的两个叶子,同时两个结点的权值加起来生成一个新结点,该新树的权值就是原来两个树的权值之和。(这里就是哈夫曼树的萌芽)这个时候还有N-1棵树(合并两棵,生成新的一棵嘛)
(2)再从剩下的N-1棵树找到两棵权值最小的,再次组合,哈夫曼树就会产生一个新结点。剩余N-2棵树(哈夫曼树不断成长)
(3)重复 1,2步骤,直到该森林中只剩下一棵树,就是哈夫曼树。
借助上面的例子,画流程图大概就是:
在这里插入图片描述

哈夫曼编码(左0右1式)

哈夫曼编码是哈夫曼树的一种使用,在上面例子中是用重量搬运的距离,但是我们也可以思考使用于加密电报和文字压缩等场景,通过变长度编码,我们可以在哈夫曼树的各个叶子结点中存放不同的文字符号

在数据通信中
若对每个字符采用相等长度的二进制位表示,称为固定长度编码;
若允许对不同字符采用不等长的二进制位表示,则称为可变长度编码。

所谓左0右1,就是从根结点开始,往左走是1,往右走是0,同时记录下走的左拐右拐,直到某个根结点,这一串01就是该根结点权值的哈夫曼编码。
在N个叶子结点中,会有N串哈夫曼编码,如果没有一串编码是另外一串编码的前缀,则称这样的编码是前缀编码,通过前缀编码可以很轻松翻译出源码。
这样会很抽象,例子:
(1)下面哪一串编码不是前缀编码?B
A {00, 01, 10, 11}
B {0, 1, 00 ,11}
C {0,10, 110, 111}
D {10, 110 ,1110, 1111}
技巧通过左0右1原则,拿着笔在草稿纸上划点,如果有一个编码的路径覆盖了某个编码,则说明不是前缀编码:
在这里插入图片描述
通过简单的划点,可以看到B选项中,00覆盖了0,11覆盖了1,这样当我们接到一串二进制哈夫曼编码,根本不知道00代表是 0 0 还是00

例:【2014】5个字符有如下4种编码方案,不是前缀编码的是:
01,0000,0001,001,1
011,000,001,010,1
000,001,010,011,100
0,100,110,1110,1100
还是通过上面划点,左0右1,很轻松能看到D选项的1100覆盖掉了110的路径
当然网上也有其它的办法,但是我比较笨看数字看得很晕,也怕看错,画图是我最喜欢的方式,一发生覆盖马上就知道了

简单一提,这样画图还有一个好处,就是哈夫曼编码的长度就等于其哈夫曼树的深度。知道了哈夫曼树的深度,就可以知道它能存放多少个字符/还能存放多少个字符。

【2015】下列给出的是从根分别到达两个叶子结点路径上的权值序列,属于同一棵哈夫曼树的是:
A 24,10,5 和 24,10,7
B 24,10,5 和24,12,7
C 24,10,10和24,14,11
D 24,10,5和24,14,6

要判断是否属于同一棵哈夫曼树,就要看从根结点开始,下一层的两个结点权值之和是否等于根结点的权值
A选项中根结点权值24,下一层如果有一个结点是权值10,则组成权值10的应该是5,5;但是A选项中却是5,7;这就是序列不合法
B选项中根结点权值24,下一层权值一个10,一个12,两个结点权值之和根本组不成24,所以也是序列不合法
C选项中根结点24,下一层一个权值10,一个权值14,合法; 权值为10的下一层一个权值是10,那么另外一个结点权值只能是0;权值为14的下一层的一个权值是11,另外一个结点权值只能是3。这个时候,既然这棵树最小是0,3;第一次组合不应该是0和3组合吗?为什么是0和10,3和11组合?这很明显就不是一棵哈夫曼树
D选项24权值的根分为权值10和权值14的结点,权值10的结点又分为5,5;权值14的分为6,8;组合合法。所以是D

【2017】已知字符集 {a,b,c,d,e,f,g,h} 各字符的哈夫曼编码依次是 0100,10,0000,0101,001,011,11,0001;则编码序列0100011001001011110101的译码结果是:
由于它已经是哈夫曼编码,所以一定不会有重复的前缀,大胆一个个读过去,同时根据哈夫曼编码,符合的一定就是对应的字母,不会有其它情况!大胆读过去:
0100 : a
011: f
001: e
001: e
011: f
11:g
0101:d

【2018】已知字符集{ a,b,c,d,e,f } ,各字符出现的次数分别是 6,3,8,2,10,4;则对应字符集中各字符的哈夫曼编码可能是:
根据哈夫曼树的原则,我们尽可能让出现次数越多的越靠前,出现次数越多,可以看作是权值越大。构建一棵二叉树,然后根据该二叉树根据左0右1的规则(也可能是左1右0的规则),生成一串哈夫曼编码。
注意由于组成对的两个结点,左右位置是任意放的,所以
在这里插入图片描述
【2012】设有6个有序表ABCDEF,分别含有10,35,40,50,60和200个数据元素,各表中的元素按升序排序。要求通过5次两两合并,将6个表重合并为1个升序表,并使最坏情况下比较的总次数达到最小,则:
(1)给出完整的合并过程,并求出最坏情况下比较的总次数
思路分析:
(由于题目要求的是最坏情况,那么最坏情况就是每对两两合并的升序表,它的值都是错开的不连续的,所以大小需要一一对比,例如10和200合并,就需要比较200+10 - 1 次,生成210个元素的有序新表后,再跟60比较,需要比较 210 + 60 -1 次,生成270个新元素的新表,综上,合并含有m和n个元素的有序表,比较次数是m + n -1 次)
这其实就很明显看出,如果一开始就合并大表,那么最坏情况,接下来每合并一张表,都要把大表循环比较一遍,导致比较次数最多。所以我们必须把大表放到最后比较。
所以这还是哈夫曼树的构造过程:
A和B合并,形成45个有序元素的新表(这里45看作新的树的权值),比较了44次
AB和C合并,形成了 45 + 40 = 85 个有序元素的新表(这里85看作新的树的权值),比较了84次
D和E合并,形成了50 + 60 = 110 个有序元素,比较109次
ABC和DE合并,形成了85+110 = 195 个有序元素,比较了194次
ABCDE和F合并,形成了195 + 200 = 395 个有序元素,比较了394次
所以共比较了:44 + 84 + 109 + 194 + 394 = 825次比较,这就是最少的比较次数
在这里插入图片描述

(2)根据你的合并过程,描述n(n>=2)个不等长升序表的合并策略,并说明理由
n个不等长升序表的合并,要按照哈夫曼树的生成原则,先进行长度最短的两个表合并形成一个新表,再在n-1个表中寻找两个长度最短的合并形成一个新表,不断进行这样的两两合并,直到只剩下1个升序表,此时就合并成功。

【2020】若任意一个字符的编码都不是其它字符编码的前缀,则称这种编码具有前缀性,现有某字符集(字符个数>=2)的不等长编码,每个字符的编码均为二进制的01序列,最长为L位,且具有前缀特性
(1)哪种数据结构适宜保存上述具有前缀特性的不等长编码?
(注意是数据结构,不能回答什么数组,链表这些存储结构!这些存储结构是数据结构的物理存储方式!)
哈夫曼树,二进制编码对应着对应字符从根结点开始往下(左0右1)的对应存放位置,二进制编码的位数表示着该叶子结点的深度,即路径长度

(2)基于设计的数据结构,简述从0/1串到字符串的译码过程
由于哈夫曼树中,对应的数据都存放在叶子结点,所以我们根据编码,从左到右依次循环,左0右1(或者左1右0),找到对应的叶子结点,就是我们需要找的字符

(3)简述判定某字符集的不等长编码是否具有前缀性的过程
不等长编码具有前缀性,最重要就是“不能覆盖别人的路径”,所以在生成的时候,把对应的不等长编码一个个读入,然后根据左0右1去寻找根结点,若有一个不等长编码覆盖了别的字符的根结点的不等长编码,则不具有前缀性。
(具体细节还可以再展开详细描述)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/19008.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

上位机工业协议-S7COMM

1、S7协议主要针对西门子相关设备通信。先了解基本通信对象、通信环境、通信报文,再处理S7COMM通信库的封装与测试。 2、西门子设备通信 - PLC:系列 LOGO、200、200Smart、300、400、1200、1500 - PLC:LOGO、200、200Smart、300、400、1…

Elastic Stack容器化部署拓展(Https、AD域集成)并收集Cisco设备的日志信息

前言: 还记得在去年的笔记中提到过EFK(Elasticsearch-Filebeat-Kibana)的部署,但是其中的内容相对简单,也没有提到一些额外的Elastic Stack的特性。链接如下:https://blog.csdn.net/tushanpeipei/article/…

JSTL使用

目录 简介: 组成 使用: code核心库使用 ​编辑 fmt格式化 ​编辑 简介: 全称:JSP Standard Tag Library 中文名:JSP标准标签库 作用:用于扩展JSP中的标签,能够为JSP页面提供流程控制、类型转换等功能的标签。替换JSP中代码…

【Spring Cloud实战】Ribbon负载均衡

gitee地址:https://gitee.com/javaxiaobear/spring-cloud_study.git 在线阅读地址:https://javaxiaobear.gitee.io/ 1、概述 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。 简单的说,Ribbon是Netflix发布的开源项…

jenkins持续集成 自动化部署

一、环境准备 1.1 Java环境 (1)安装jdk1.8 yum -y install java-1.8.0-openjdk* (2)执行以下命令查看是否安装成功 java -version 1.2 安装maven (1)将安装包上传到Linux服务器,解压缩 tar -…

对笔记本电池的研究

文章目录设计容量&完全充电容量笔记本电池报告显示电池设计与系统电池的全部充电容量之间的差异解释电池损耗正确做法查看笔记本的电池使用报告方法第一步:WinR键输入cmd,打开命令提示符窗口第二步:输入powercfg /batteryreport&#xff…

代码规范-对抗软件复杂度

1、为什么需要代码规范 任何系统性的项目都需要架构设计,而架构设计的核心命题是控制复杂度。 但随着项目的不断迭代,复杂度就会不断上升,研发效率就会不断下降。 而代码规范正是对抗软件复杂度的有效手段,通过约定俗成的规则…

[附源码]计算机毕业设计JAVA户籍管理系统

[附源码]计算机毕业设计JAVA户籍管理系统 项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis M…

docker安装redis详细教程

1、下载最新redis镜像 docker pull redis //表示拉取最新的镜像 如果要指定版本 docker pull redis:latest//表示拉取最新的镜像 2、创建redis映射目录 mkdir /redisData/redis/conf 配置文件挂载在我指定的redisData/redis/conf/ 文件夹中,方便后续的修改 创建re…

Linux上单机部署RocketMq

Linux上单机部署RocketMq1、安装jdk2、下载rocketmq并解压3、创建日志文件夹4、启动namesrv5、启动broker6、查看和关闭7、rocketmq控制台7.1、控制台idea启动7.2、控制台jar包启动1、安装jdk rocketmq的运行是建立在jdk之上的,所以,我们要搭建rocketmq服…

uView u-slider 自定义滑块

有个需求UI设计的滑动选择器中的滑块如下所示: 项目中集成的是vView2.0组件库,u-slider组件中有 blockStyle 属性,看着是用来设置自定义滑块的。但是试了下,没有效果,不知怎么回事。看了一下uView1.0组件库 u-slider组…

大学生想做兼职应该怎么找,适合大学生的线上线下靠谱兼职推荐

大学生现在有很多兼职工作可以在网上和实体上做。他们可以根据个人能力和喜好进行选择。以下是一些低门槛的在线和离线兼职工作,希望能帮助到你。 线下兼职 1.勤工助学岗位 学校:通过学校提供的勤工俭学岗位,如办公室助理、图书馆助理等&am…

Java 线上机器 CPU 100% 的一次排查过程

文章目录1. 问题发生2. 数据库连接关闭问题排查3. 问题的进一步排查4. 解决方法1. 问题发生 日常敲代码突然收到生产环境异常告警,线上有一台机器 CPU 使用率飙升到 100 触发扩容,工作群里一下子鸡飞狗跳。 出现问题,首先当然是查看监控和日…

如何画架构图?

平时做过一些系统设计,也写过一些系统分析文章,从组件、关系、交互等方面提供一些建议,并用我之前写文章画的一些图举些例子。构成系统的组件通过形状、颜色、名称来逼近其概念。LevelDB 主要构件如上面 LevelDB 的架构图,包含的主…

Redis哨兵(Sentinel)

# Redis哨兵(Sentinel) Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务: 监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常…

内核参数 sched_min_granularity_ns 为什么看不到啦?

linux内核从版本v5.13-rc1起(含),sysctl 已无法设置 kernel.sched_min_granularity_ns。 其实不止sched_min_granularity_ns,在 /proc/sys/kernel 下,和CPU调度相关的6个参数都不见了: sched_latency_ns …

Unity VR开发教程 OpenXR+XR Interaction Toolkit 2.1.1(七)射线抓取

文章目录📕教程说明📕添加射线功能的相关组件📕设置 Interaction Layer Mask📕让 XR Direct Interactor 不对 XR Ray Interactor 产生干扰📕使抓取的物体不会吸到手上📕远距离抓取时通过摇杆改变抓取物体的…

Node.js安装及环境配置

Node.js安装及环境配置1.下载安装Node.js2.npm安装路径配置3.环境变量配置4.换源5.测试npm安装1.下载安装Node.js Node.js官网 下载如图所示版本:(请根据自己的系统环境选择) 下载完成后傻瓜式安装即可 测试环境: PS C:\Users…

终于拿到了爆火全网的进一线大厂程序员必看的1700道java面试题

爆火全网的进一线大厂程序员必看的1700道java面试题到底有多牛? 牛不牛不敢说,但是有好多程序员是靠这一套1700道高频面试题,顺利收到很多大厂offer! 以至于,到现在为止,大厂都开始按照这一套1700道面试题…

java计算机毕业设计ssm美食视频教学网站element 前后端分离

项目介绍 高校实验室信息管理平台是使用JAVA的SSM技术,MySQL作为数据库开发,用户通过查看实验室信息,在线预约实验室,实现高校实验室信息化管理。首先对本论文进行分析后,提出平台的相关技术,然后整理系统的需求分析,根据需求进行功能和数据库设计,最后进行系统实现和测试 。 …