哈夫曼树与哈夫曼编码

哈夫曼树与哈夫曼编码

哈夫曼树

哈夫曼树又称最优二叉树,这种数据结构主要用于解决一些编码问题,与普通二叉树相比,哈夫曼树在特定场景下能够显著的提高效率。

相关概念

权值:指哈夫曼树叶子节点的权值,例如上图中哈夫曼树树的叶子节点权值为2,5,8,10

路径长度:指从根节点出发,到达叶子节点所经过的边的数目,例如上图中权值为2的节点路径长度为3

树的路径长度:树的路径长度等于这颗树中所有节点的路径长度之和,包括叶子节点和非叶子节点,例如上图中这颗哈夫曼树的路径长度=1+1+2+2+3+3

结点的带权路径长度:结点的带权路径长度等于结点的路径长度×结点的权值,一般认为结点的带权路径长度指的是叶子结点的带权路径长度,例如上图权值为2的结点的带权路径长度=2*3

树的带权路径长度:树的带权路径长度等于这颗哈夫曼树中所有叶子节点的带权路径长度之和,称为WPL(weight path length)

如何构建一颗哈夫曼树?

哈夫曼树要求整个树的WPL值最小,根据WPL的计算规则,在构建哈夫曼树时,需要让权值大的叶子节点靠近根节点,权值小的叶子节点远离根节点。构建哈夫曼树的一般步骤如下:

  1. 选取权值最小的2个节点进行合并,合并之后的父节点权值=左节点权值+右节点权值(一般权值小的节点在左,权值较大的节点在右)

  2. 将父节点与其它叶子节点按照相同的规则进行合并,直到最终只剩下一个节点

  3. 以[2,5,8,10]为例说明上述过程

    在这里插入图片描述

C++代码实现:

#define VALUE_INDEX 0
#define LEFT_INDEX 1
#define RIGHT_INDEX 2
#define FATHER_INDEX 3
vector<vector<int>> CreateHuffmanTree(const vector<int>& nodes) {
	int n = nodes.size();
	vector<vector<int>> huffman(2 * n, vector<int>(4));
	auto pairCompare = [](const pair<int, int>& l, const pair<int, int>& r) {
		return l.second > r.second;//小堆
	};
	priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(pairCompare)> heap(pairCompare);
	for (int i = 0; i < n; i++) {
		huffman[i + 1][VALUE_INDEX] = nodes[i];
		heap.push(std::make_pair(i + 1, nodes[i]));
	}
	int index = n + 1;//从n+1下标开始填
	while (index < 2 * n) {
		pair<int, int> x = heap.top();
		heap.pop();
		pair<int, int> y = heap.top();
		heap.pop();
		huffman[x.first][FATHER_INDEX] = index;
		huffman[y.first][FATHER_INDEX] = index;
		huffman[index][VALUE_INDEX] = x.second + y.second;
		huffman[index][LEFT_INDEX] = x.first;
		huffman[index][RIGHT_INDEX] = y.first;
		heap.push(std::make_pair(index, huffman[index][VALUE_INDEX]));
		index++;
	}
	return huffman;
}

说明:

  • 参数nodes表示所有给定叶子节点的权值(可以出现重复值)

  • 这里使用了二维数组作为整个树的逻辑结构,huffman数组中的每一个元素表示一个节点的信息,数组的下标表示节点的编号,例如huffman[2][VALUE_INDEX]表示编号为2的节点对应的权值,huffman[2][LEFT_INDEX]表示编号为2的节点的左节点编号,huffman[2][RIGHT_INDEX]表示编号为2的节点的右节点编号,huffman[2][FATHER_INDEX]表示编号为2的节点的父节点编号

  • 对于任意一颗哈夫曼树,都只有度为0的节点或者度为2的节点,不存在度为1的节点,由于二叉树n=n0+n1+n2,且n0=n2+1,所以任意一颗哈夫曼树的节点总数n=2n0-1,因此二维数组的大小至少开到2n0-1,但是实际上我们将二维数组的大小开到了2n0,并且弃用了0号下标,原因如下:

    1. 二维数组在初始化时,所有元素均为0,父节点编号为0可以表示不存在父节点,即这个节点是最终构建出来的哈夫曼树的根节点,左右节点编号为0表示左右节点为空,当前节点为叶子节点
    2. 如果将0号下标进行使用,那么当一个元素的父节点编号为0时,是表示这个节点为根节点?还是说这个节点不是根节点,它的父节点是编号为0的节点?
  • 在构建哈夫曼树的过程中,使用了堆,因为我们每一次都需要选择最小的2个节点进行合并,并且这2个节点不能是已经选择过的,如果采用遍历操作,时间复杂度为O(N),使用堆可以加速这一过程

  • 使用上述方案,给定叶子节点为[2,5,8,10],构建出来的哈夫曼树结果如下

    在这里插入图片描述

哈夫曼编码

哈夫曼编码是一种前缀编码,可以将一个字符串编码为一串01序列,编码出来的01序列具有如下特点:

  1. 解码方式唯一,不存在任何歧义
  2. 对于出现频率高的字符,对应的01序列较短,对于出现频率低的字符,对应的01序列长
  3. 通过哈夫曼编码得到的01序列可以保证比大部分其它方式编码得到的01序列短,也就意为着在进行网络传输过程中发送的数据量要更少

前缀编码

使用前缀编码得到的01序列在解码时不会出现歧义,而使用其它编码得到的01序列在进行解码时可能会出现歧义,例如对于"ABC"这个字符串进行编码,规定如下表示方法:

'A' 0
'B' 00
'C' 1

则"ABC"对应的二进制序列为0001,在进行解码时,可以有多种解释,包括"ABC"、“BAC”、“AAAC”,根本原因在于设置编码规则时,'A’对应的编码0为字符’B’对应的编码00的前缀。而以哈夫曼编码为代表的前缀编码就不存在类似问题

生成哈夫曼编码

依然以[2,5,8,10]为例,假设有一个字符串,有2个字符’A’,5个字符’B’,8个字符’C’,10个字符’D’组成,那么生成这个字符串的哈夫曼编码流程如下:

  1. 以[2,5,8,10]为权值,构建哈夫曼树

    在这里插入图片描述

  2. 规定向左的边码值为0,向右的边码值为1,那么’D’的哈夫曼编码为0,'A’的哈夫曼编码为100,'B’的哈夫曼编码为101,'C’的哈夫曼编码为11

  3. 可以看出,出现频率越高的字符对应的哈夫曼编码越短,并且不存在任意一个字符的编码为另外一个字符的编码前缀,因为这些字符都是对应的叶子节点,因此哈夫曼编码在进行编码与解码时不存在歧义

C++代码实现:

void DisPlayHuffmanCode(const vector<vector<int>>& huffmanTree) {
	int n0 = huffmanTree.size()/2;//叶子节点的个数
	for (int i = 1; i <= n0; i++) {
		string code;
		int cur = i;
		while (huffmanTree[cur][FATHER_INDEX]) {
			int fIndex = huffmanTree[cur][FATHER_INDEX];
			code += huffmanTree[fIndex][LEFT_INDEX] == cur ? '0' : '1';
			cur = fIndex;
		}
		std::reverse(code.begin(), code.end());
		std::cout << "权值为" << huffmanTree[i][VALUE_INDEX] << "的节点对应的哈夫曼编码是:" << code << std::endl;
	}
}

给定权值为[2,5,8,10],哈夫曼编码结果如下:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

07:STM32----ADC模数转化器

目录 1:简历 2:逐次逼近型ADC 3:ADC基本结构 4:输入通道 5:规则组的4种转换模式 1:单次转化,非扫描模式 2:连续转化,非扫描模式 3:单次转化,扫描模式 4:单次转化,扫描模式 6:触发控制 7:数据对齐 8:转化时间 9:校准 10:ADC的硬件电路 A: AD单通道 1:连接图 2:函…

计算机竞赛 基于机器视觉的二维码识别检测 - opencv 二维码 识别检测 机器视觉

文章目录 0 简介1 二维码检测2 算法实现流程3 特征提取4 特征分类5 后处理6 代码实现5 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器学习的二维码识别检测 - opencv 二维码 识别检测 机器视觉 该项目较为新颖&#xff0c;适合作为竞赛课…

【多线程案例】单例模式(懒汉模式和饿汉模式)

文章目录 1. 什么是单例模式&#xff1f;2. 立即加载/“饿汉模式”3. 延时加载/“懒汉模式”3.1 第一版3.2 第二版3.3 第三版3.4 第四版 1. 什么是单例模式&#xff1f; 提起单例模式&#xff0c;就必须介绍设计模式&#xff0c;而设计模式就是在软件设计中&#xff0c;针对特殊…

6路液体水位检测芯片VK36W6D SOP16 抗电源干扰及手机干扰特性好

产品品牌&#xff1a;永嘉微电/VINKA 产品型号&#xff1a;VK36W6D 封装形式&#xff1a;SOP16/QFN16L 详细资料&#xff1a;13.5/5.474/4.703 概述 VK36W6D具有6个触摸检测通道&#xff0c;可用来检测6个点的水位。该芯片具有较高的集成度&#xff0c;仅需极少的外部组件便…

一文了解tcp/ip协议的运行原理

接触代理ip的人都了解https/sock5等ip协议&#xff0c;那么TCP/IP 协议又是什么&#xff1f; 一、什么是TCP/IP 协议&#xff1f; TCP/IP 协议实际上是一系列网络通信协议的一个统称&#xff0c;他负责具体的数据传输工作&#xff0c;核心的两个协议包括TCP以及IP&#xff0c…

25.选择排序,归并排序,基数排序

目录 一. 选择排序 &#xff08;1&#xff09;简单选择排序 &#xff08;2&#xff09;堆排序 二. 归并排序 三. 基数排序 四. 各种排序方法的比较 &#xff08;1&#xff09;时间性能 &#xff08;2&#xff09;空间性能 &#xff08;3&#xff09;排序方法的稳定性能…

美创科技获通信网络安全服务能力评定(应急响应一级)认证!

近日&#xff0c;中国通信企业协会公布通信网络安全服务能力评定2023年第一批获证企业名单。 美创科技获得应急响应一级资质&#xff0c;成为2023年第一批获证企业之一&#xff01; 通信网络安全服务能力评定是对通信网络安全服务单位从事通信网络安全服务综合能力的评定&#…

Revit SDK 介绍:CreateAirHandler 创建户式风管机

前言 这个例子介绍如何通过 API 创建一个户式风管机族的内容&#xff0c;包含几何和接头。 内容 效果 核心逻辑 必须打开机械设备的族模板创建几何实体来表示风管机创建风机的接头 创建几何实体来表示风管机 例子中创建了多个拉伸&#xff0c;下面仅截取一段代码&#xff…

python爬虫—requests

一、安装 pip install requests 二、基本使用 1、基本使用 类型 &#xff1a; models.Response r.text : 获取网站源码 r.encoding &#xff1a;访问或定制编码方式 r.url &#xff1a;获取请求的 url r.content &#xff1a;响应的字节类型 r.status_code &#xff1a;响应…

山西省文物局与大势智慧签订战略合作协议

8月24日&#xff0c;由山西省文物局、中国文物信息咨询中心(国家文物局数据中心)主办的数字文博发展论坛在太原举行。武汉大势智慧科技有限公司&#xff08;后简称“大势智慧”&#xff09;受邀参与&#xff0c;与来自国内文博数字化领域的专家学者齐聚一堂&#xff0c;围绕“数…

什么是同源策略(same-origin policy)?它对AJAX有什么影响?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 同源策略&#xff08;Same-Origin Policy&#xff09;与 AJAX 影响⭐ 同源策略的限制⭐ AJAX 请求受同源策略影响⭐ 跨域资源共享&#xff08;CORS&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记…

K 次取反后最大化的数组和【贪心算法】

1005 . K 次取反后最大化的数组和 给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数组&#xff1a; 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这个过程恰好 k 次。可以多次选择同一个下标 i 。 以这种方式修改数组后&#xff0c;返回数组 可能…

02_nodejs开发环境安装

02 【nodejs开发环境安装】 1.版本介绍 在命令窗口中输入 node -v 可以查看版本0.x 完全不技术 ES64.x 部分支持 ES6 特性5.x 部分支持ES6特性&#xff08;比4.x多些&#xff09;&#xff0c;属于过渡产品&#xff0c;现在来说应该没有什么理由去用这个了6.x 支持98%的 ES6 特…

zabbix安装部署

前期准备&#xff1a;安装mysql数据库和nginx 一、下载zabbix rpm -Uvh https://repo.zabbix.com/zabbix/4.4/rhel/7/x86_64/zabbix-release-4.4-1.el7.noarch.rpm yum-config-manager --enable rhel-7-server-optional-rpms yum install epel-release numactl yum install…

Metasploit“MSF”连接postgresql时因排序规则版本不匹配导致无法连接

一、问题 更新Kali之后使用Metasploit时出现一个问题&#xff0c;连接postgresql时因排序规则版本不匹配导致无法连接 警告: database "msf" has a collation version mismatch DETAIL: The database was created using collation version 2.36, but the operati…

Linux操作系统中的信号剖析,

1、前言 信号是一种信息载体&#xff0c;在现实中&#xff0c;信号就是表示消息的物理量&#xff0c;比如说红绿灯&#xff0c;古时候狼烟等等&#xff0c;就拿红绿灯来说&#xff0c;为什人和车辆都是看到绿灯才会通行&#xff0c;红灯亮了就要停下来&#xff0c;因为这是现实…

Dolphin for Mac(Wii游戏模拟器)配置指南

Wii模拟器Dolphin Mac是款适合Mac电脑中的游戏玩家们使用的模拟器工具。Wii模拟器Dolphin Mac官方版支持直接运行游戏镜像文件&#xff0c;玩家可以将游戏ISO拷贝到某一个文件夹中统一进行管理。Wii模拟器Dolphin Mac除了键盘和鼠标外&#xff0c;还支持配合原版的Wii遥控器操作…

1、[春秋云镜]CVE-2022-32991

文章目录 一、相关信息二、解题思路&#xff08;手注&#xff09;三、通关思路&#xff08;sqlmap&#xff09; 一、相关信息 靶场提示&#xff1a;该CMS的welcome.php中存在SQL注入攻击。 NVD关于漏洞的描述&#xff1a; 注入点不仅在eid处&#xff01;&#xff01;&#xff…

Screaming Frog SEO Spider,为您的网站提供全方位的优化解决方案

Screaming Frog SEO Spider是一款适用于Mac的软件&#xff0c;它可以帮助用户分析网站的优化信息。该软件可以模拟蜘蛛爬行的方式&#xff0c;抓取网站的各种信息&#xff0c;并将这些信息整理成易于理解的报告。这些报告可以帮助用户评估网站的优化情况&#xff0c;发现链接的…

前端将UTC时间格式转化为本地时间格式~~uniapp写法

UTC时间格式是什么 首先我们先简单的了解一下&#xff1a;UTC时间&#xff08;协调世界时&#xff0c;Coordinated Universal Time&#xff09;使用24小时制&#xff0c;以小时、分钟、秒和毫秒来表示时间 HH:mm:ss.SSSHH 表示小时&#xff0c;取值范围为00到23。mm 表示分钟…