4-4 哈夫曼编码

news2024/11/25 2:35:24

 


  • 博主简介:一个爱打游戏的计算机专业学生
  • 博主主页: @夏驰和徐策
  • 所属专栏:算法设计与分析

1.什么是哈夫曼编码?

哈夫曼编码(Huffman coding)是一种用于数据压缩的无损编码方法。它是由David A. Huffman在1952年提出的,被广泛应用于通信和存储领域。

哈夫曼编码通过对不同符号赋予不同长度的编码,使得出现频率高的符号使用较短的编码,而出现频率低的符号使用较长的编码,以此来实现数据压缩。哈夫曼编码的关键思想是利用变长编码来表达符号,使得出现频率高的符号的编码比出现频率低的符号的编码更短,从而减少整体的编码长度。

哈夫曼编码的构建过程如下:
1. 统计符号的出现频率:遍历待编码的符号序列,统计每个符号出现的频率。
2. 构建哈夫曼树:根据符号频率构建哈夫曼树。频率越高的符号离根节点越近,频率越低的符号离根节点越远。
3. 分配编码:从根节点开始,为哈夫曼树的每个叶子节点分配一个编码。沿着左子树走为0,沿着右子树走为1。最终,每个符号都有一个唯一的二进制编码。
4. 压缩数据:将原始数据中的每个符号替换为对应的哈夫曼编码,从而实现数据的压缩。

由于哈夫曼编码使用变长编码,可以根据符号的出现频率进行最优编码,因此哈夫曼编码可以实现无损压缩,即在解码时完全还原原始数据。哈夫曼编码被广泛应用于数据压缩、图像压缩、音频压缩等领域。

 2.什么是前缀码

前缀码(Prefix code)是一种编码方式,其中没有任何一个编码是另一个编码的前缀。换句话说,前缀码中的每个编码都不是其他编码的前缀。

前缀码的主要特点是具有唯一解码性。由于没有编码是其他编码的前缀,所以在解码时可以根据编码的唯一性来还原原始数据,无需使用特殊的结束标记或其他辅助信息。

哈夫曼编码是一种常见的前缀码。在哈夫曼编码中,根据符号出现的频率,将出现频率高的符号赋予较短的编码,而出现频率低的符号赋予较长的编码。由于哈夫曼编码是前缀码,所以在解码时可以通过识别编码的唯一性来还原原始数据。

前缀码具有高效的压缩性能和解码速度。在通信和数据存储中,前缀码常被用于数据压缩、图像压缩、音频压缩等领域,以减少数据的传输和存储成本。

 

3.如何构造哈夫曼编码?

构造哈夫曼编码的步骤如下:

1. 统计符号的出现频率:遍历待编码的符号序列,统计每个符号出现的频率。可以使用一个频率表或者堆数据结构来记录符号和频率的对应关系。

2. 构建哈夫曼树:根据符号频率构建哈夫曼树。首先,将每个符号视为一个独立的树节点,并根据频率将这些节点组成森林(每个节点是一棵单节点的树)。然后,重复以下步骤直到只剩下一棵树:
   - 选择频率最低的两个树节点,将它们作为左右子树创建一个新的父节点,并将父节点的频率设为左右子树节点的频率之和。
   - 将新创建的父节点加入到森林中。
   - 从森林中移除被合并的两个节点。

3. 分配编码:从哈夫曼树的根节点开始,为每个叶子节点分配一个编码。遍历哈夫曼树的路径,当向左子树移动时,添加一个0到编码中;当向右子树移动时,添加一个1到编码中。最终,每个符号都将有一个唯一的二进制编码。

4. 压缩数据:将原始数据中的每个符号替换为对应的哈夫曼编码,从而实现数据的压缩。

构造哈夫曼编码的关键在于构建哈夫曼树和分配编码的过程。哈夫曼树的构建基于贪心算法,通过合并频率最低的节点来构建树。分配编码时,通过深度优先遍历哈夫曼树的路径来为每个叶子节点分配编码。

注意,构造哈夫曼编码时,为了确保编码的唯一性,需要保证符号的频率已经预先给定,且频率较高的符号具有较短的编码。

 

 4.算法用的类Huffman定义如下:

template<class Type>
class Huffman
{
	friend BinaryTree<int> HuffmanTree(Type[], int);
public:
	operator Type ()const { return weight; }
private:
	BinaryTree<int> tree;
	Type weight;
};

我的理解:

这段代码是一个Huffman编码的实现。Huffman编码是一种用于数据压缩的算法,通过将出现频率较高的字符用较短的编码表示,来实现对数据的高效压缩。

代码中定义了一个名为Huffman的模板类,该类具有一个模板参数Type,表示编码的数据类型。类中有一个友元函数HuffmanTree,返回一个BinaryTree<int>类型的对象,表示Huffman编码树。类中还有一个类型转换运算符,用于将对象转换为Type类型,返回权重(weight)。

模板类Huffman包含以下成员:
- BinaryTree<int> tree: 一个BinaryTree<int>类型的对象,表示Huffman编码树。
- Type weight: 表示权重(weight),即字符出现的频率或权值。

在实际使用时,可以根据具体的需求实例化Huffman类,并调用HuffmanTree函数来构建Huffman编码树。

 5.哈夫曼算法的代码实现:

template <class Type>
BinaryTree<int> HuffmanTree(Type f[], int n)
{
	Huffman<Type>* w = new Huffman<Type>[n + 1];
	BinaryTree<int> z, zero;
	for (int i = 1; i <= n; i++)
	{
		z.MakeTree(i, zero, zero);
		w[i].weight = f[i];
		w[i].tree = z;
	}
	//建立优先队列
	MinHeap<Huffman<Type>>Q(1);
	Q.Initialize(w, n, n);
	//反复合成最小频率树
	Huffman<Type> x, y;
	for (int i = 1; i < n; i++)
	{
		Q.DeleteMin(x);
		Q.DeleteMin(y);
		z.MakeTree(0, x.tree, y.tree);
		x.weight += y.weight;
		x.tree = z;
		Q.Insert(x);
	}
	Q.DeleteMin(x);
	Q.Deactivate();
	delete[]w;
	return x.tree;
}

我的理解:

这段代码实现了Huffman编码树的构建过程。

首先,函数HuffmanTree是一个模板函数,接受两个参数:一个类型为Type的数组f[],表示每个字符的频率或权值;一个整数n,表示数组中元素的数量。

在函数内部,首先创建了一个长度为n+1的Huffman类型的指针数组w,用于存储Huffman类的对象。然后创建了两个BinaryTree<int>类型的对象z和zero。

接下来,通过一个循环遍历数组f[],为每个元素创建一个Huffman对象,并将权重设置为对应的频率值,同时将BinaryTree对象设置为z。这样就得到了n个具有权重和二叉树的Huffman对象。

接下来,代码通过创建一个MinHeap对象Q来建立优先队列,用于按照权重值对Huffman对象进行排序和管理。Q.Initialize函数用于初始化优先队列,并将Huffman对象数组w中的元素添加到优先队列中。

然后,代码通过一个循环反复合成最小频率的树。循环中,每次从优先队列中删除权重最小的两个Huffman对象x和y,创建一个新的BinaryTree对象z,将x和y的二叉树作为子树连接到z上,然后将x的权重更新为x和y权重的和,并将z设置为x的二叉树。最后,将更新后的x对象重新插入优先队列中。

最后,从优先队列中删除剩下的最后一个Huffman对象x,将优先队列禁用,释放之前动态分配的内存,并返回x对象的二叉树作为Huffman编码树。

总体而言,这段代码通过构建Huffman对象和使用优先队列来实现了Huffman编码树的构建过程。

6.哈夫曼算法的正确性 

哈夫曼算法的正确性可以通过以下两个方面来解释:

1. 哈夫曼编码的前缀码性质:哈夫曼编码是一种前缀码,即没有任何一个编码是其他编码的前缀。这意味着在解码时,我们可以通过唯一性地识别每个编码来还原原始数据,而无需使用特殊的结束标记或其他辅助信息。这个前缀码性质是哈夫曼算法的核心特点之一,它确保了编码和解码的一致性,从而保证了正确性。

2. 哈夫曼树的构建:哈夫曼算法通过构建哈夫曼树来生成编码。在哈夫曼树的构建过程中,通过贪心策略,将频率最低的两个节点合并为一个新节点,并按照频率从小到大的顺序进行合并,直到最终只剩下一个根节点。这个贪心策略确保了生成的哈夫曼树的叶子节点对应于原始符号,并且频率较高的符号位于树的较浅层,频率较低的符号位于树的较深层。因此,编码树的构建确保了频率较高的符号获得较短的编码,而频率较低的符号获得较长的编码。

综上所述,哈夫曼算法的正确性可以通过哈夫曼编码的前缀码性质和哈夫曼树的构建过程来解释。这些特性确保了编码的一致性和最优性,从而实现了正确的数据压缩和解压缩。

 总结:

哈夫曼编码的贪心算法在实现过程中有几个重点、难点和易错点:

1. 频率统计:正确地统计每个符号的出现频率是关键。在哈夫曼编码的过程中,需要准确地知道每个符号的频率,以便构建哈夫曼树和分配编码。确保频率统计的准确性是算法的重点和难点之一。

2. 哈夫曼树的构建:构建哈夫曼树的过程涉及到合并节点和更新频率。在每一步选择频率最低的两个节点进行合并,并将新节点的频率设置为这两个节点的频率之和。正确地合并节点和更新频率是算法的重点和难点之一。

3. 编码的分配:为每个叶子节点分配唯一的编码是哈夫曼编码的关键。编码的分配需要根据哈夫曼树的结构进行遍历,并沿着左子树走为0,沿着右子树走为1,为每个叶子节点分配对应的编码。确保编码的唯一性和正确性是算法的重点和难点之一。

4. 数据压缩与解压缩的一致性:在使用哈夫曼编码进行数据压缩时,需要确保压缩和解压缩过程的一致性。即确保编码和解码的逻辑相同,以保证数据能够正确地还原。在实现压缩和解压缩算法时,要特别注意确保数据的正确性和完整性。

总体而言,哈夫曼编码的贪心算法的重点在于准确地统计频率、构建哈夫曼树、分配编码,并保证数据压缩和解压缩的一致性。在实现过程中,需要仔细处理这些关键步骤,避免常见的易错点,以确保算法的正确性和有效性。

 

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

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

相关文章

STM32F4_软件模拟SPI

目录 1. 硬件连接 2. SPI通讯协议 3. W25Q64 简介 4. 程序详解 4.1 main.c 4.2 SPI.c 4.3 SPI.h 4.4 W25Q128.c 4.5 W25Q128.h 4.6 OLED.c 4.7 OLED.h 4.8 OLED_Font.h 5. 实验结果 我们都知道&#xff0c;SPI 和 IIC 一样&#xff0c;都可以通过硬件方式和软件方…

JSON基础(待补充)

一、JSON初识 1.1基础认识 JSON是一种轻量级的数据交换格式&#xff0c;它基于JavaScript语言的对象表示法&#xff0c;可以在多种语言之间进行数据交换。JSON的基本数据类型有数值、字符串、布尔值、数组、对象和空值。JSON的格式简洁易读&#xff0c;也易于解析和处理。JSON…

【数据结构】由完全二叉树引申出的堆的实现

【数据结构】由完全二叉树引申出的堆的实现 一、什么是堆二、目标三、实现1、初始化工作2、堆的插入(堆的创建)2.1、向上调整建堆2.1.1、向上调整算法原理解析2.1.2、代码实现 2.2、向下调整建堆2.2.1、向下调整算法原理解析2.2.2、代码实现 2.3、“向上”和“向下”复杂度的差…

初识网络安全

目录 HTML前置基础知识 1、id和class区别&#xff1a; 2、一些常用的属性&#xff1a; 3、HTML字符编码和实体编码 4、URL介绍 网址的组成部分&#xff1a; TTL值 DNS工作原理和资源记录及其种类&#xff1a; 5、正确区分“加密”和“签名” 6、状态码 1xx &#xf…

如何安装pycharm

PyCharm是JetBrains公司推出的一款Python集成开发环境&#xff08;IDE&#xff09;&#xff0c;可以提供高效的Python代码编写、调试和测试。以下是一些PyCharm的主要功能&#xff1a; 代码智能提示和自动补全功能&#xff1b;支持调试和测试Python代码&#xff1b;完整的Pyth…

基于Springboot+Vue的幼儿园管理系统设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架下…

汽车相关知识及术语

1 汽车构造与制造流程 1.1 汽车构造 汽车可以分为四大部分 车身&#xff1a; 骨架、车身钣金件以及座椅、仪表、天窗、车外后视镜等车身附件 动力系统&#xff1a; 发动机和变速器 底盘&#xff1a; 传动系统、悬架系统、转向系统、制动系统和车轮轮胎 电气电子系统&#…

《Apollo 智能驾驶进阶课程》三、无人车自定位技术

1. 什么是无人车自定位系统 相对一个坐标系来确定无人车的位置和姿态 定位的指标要求大概分为三个部分&#xff1a;精度、鲁棒性、场景 定位精度必须控制在10厘米以内&#xff0c;才能使行驶中的自动驾驶车辆避免出现碰撞/车道偏离的情况。鲁棒性一般情况下用最大值来衡量。…

Java IO流详细教程

目录 一、IO介绍 IO流体系 字节流 字节输出流&#xff1a;FileoutputStream 字节输入流FilelnputStream 字符流 字符输入流 字符输出流 缓冲流 字节缓冲流 字符缓冲流 序列化、反序列化流 序列化/对象操作输出流 反序列化/对象操作输入流 打印流 字节打印流 字…

firewalld与iptables练习

1、禁止一个IP访问 iptables -I INPUT -s $ip -j REJECT 2、清空默认的防火墙默认规则&#xff1a; iptables -F 3、保存清空后的防火墙规则表 service iptables save 4、firewall-cmd --list-all #查看防火墙规则&#xff08;只显示/etc/firewalld/zones/public.xml中防火墙…

投票活动链接创建微信链接视频投票线上免费投票链接

近些年来&#xff0c;第三方的微信投票制作平台如雨后春笋般络绎不绝。随着手机的互联网的发展及微信开放平台各项基于手机能力的开放&#xff0c;更多人选择微信投票小程序平台&#xff0c;因为它有非常大的优势。 1.它比起微信公众号自带的投票系统、传统的H5投票系统有可以图…

从零手写操作系统之RVOS协作式多任务切换实现-03

从零手写操作系统之RVOS协作式多任务切换实现-03 任务&#xff08;task&#xff09;多任务 &#xff08;Multitask&#xff09;任务上下文&#xff08;Context&#xff09;多任务系统的分类协作式多任务 创建和初始化第 1 号任务切换到第一号任务执行协作式多任务 - 调度初始化…

字典树算法(C/C++)

目录 一、字典树算法的概念介绍 二、字典树算法的实现 三、例题 &#xff08;注&#xff1a;借鉴蓝桥杯国赛特训营&#xff09; 一、字典树算法的概念介绍 首先我们看下字典的组织方式 Trie 的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效…

实训总结-----Scrapy爬虫

1.安装指令 pip install scrapy 2.创建 scrapy 项目 任意终端 进入到目录(用于存储我们的项目) scrapy startproject 项目名 会在目录下面 创建一个以 项目名 命名的文件夹 终端也会有提示 cd 项目名 scrapy genspider example example.com 3.运行爬虫指令 scrapy craw…

ffmpeg之AVFormatContext结构体详细解释

AVFormatContext 作用 AVFormatContext主要起到了管理和存储媒体文件相关信息的作用。它是一个比较重要的结构体&#xff0c;在FFmpeg中用于表示媒体文件的格式上下文&#xff0c;其中包含了已经打开的媒体文件的详细信息&#xff0c;包括媒体文件的格式、媒体流的信息、各个媒…

【笔记】使用电脑连接树莓派 并在电脑屏幕上显示树莓派桌面(无需额外为树莓派购买显示器)

一、前言 想在树莓派上跑 yolo5&#xff0c;为了方便地看到代码的检测结果&#xff0c;需要为树莓派外接显示器&#xff0c;但是手头并没有额外的显示器&#xff0c;于是想在电脑屏幕上显示树莓派的桌面&#xff0c;对解决的过程作一些记录。 二、基本流程 树莓派系统的烧录…

c++11 标准模板(STL)(std::bitset)(三)

定义于头文件 <bitset> template< std::size_t N > class bitset; 类模板 bitset 表示一个 N 位的固定大小序列。可以用标准逻辑运算符操作位集&#xff0c;并将它与字符串和整数相互转换。 bitset 满足可复制构造 (CopyConstructible) 及可复制赋值 (CopyAssign…

【SpringMVC】请求与响应

1&#xff0c;PostMan工具的使用 1. PostMan简介 代码编写完后&#xff0c;我们要想测试&#xff0c;只需要打开浏览器直接输入地址发送请求即可。发送的是GET请求可以直接使用浏览器&#xff0c;但是如果要发送的是POST请求呢? 如果要求发送的是post请求&#xff0c;我们就…

基于前推回代法的连续潮流计算研究【IEEE33节点】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

从零搭建微服务-网关中心(一)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff1a;https://gitee.com/csps/mingyue 文档地址&#xff1a;https://gitee.com/csps/mingyue/wikis 新建 mingyue-gateway 在 【从零搭建微服务…