文章目录

  • 前言
  • 一、什么是文件压缩?
  • 二、为什么需要文件压缩
  • 三、怎样实现文件压缩
  • 四、创建哈夫曼树
    • 1.哈夫曼编码的方式
    • 2.构建一棵哈夫曼树
  • 五、压缩
    • 1.获取原文件中每个字节出现的次数
    • 2.根据字节出现的频次信息构建Huffman树
    • 3.获取Huffman编码
    • 4.使用Huffman编码来改写文件(压缩)
  • 六、解压缩
    • 1.获取解压缩用到的信息
    • 2.恢复哈夫曼树
    • 3.恢复原文件(解压缩)
  • 总结

前言

文件压缩的概念在生活中已经屡见不鲜,在这个信息化的时代,我们每天的生活基本上离不开手机电脑,在手机或电脑上下载软件,应用,基本上都能接触到文件压缩。对于文件压缩来讲,有许多种不同的方式,每种方式也有各自的优缺点,这篇文章,就主要介绍以哈夫曼编码的方式来实现文件压缩。


以下是本篇文章正文内容,下面案例可供参考,如有问题,还请大佬及时指正,交流学习!!!

一、什么是文件压缩?

文件压缩是指在不丢失有用信息的前提下,缩减数据量以减少存储空间,提高其传输、存储和处理效率,或按照一定的算法对文件中数据进行重新组织,减少数据的冗余和存储的空间的一种技术方法。

二、为什么需要文件压缩

  1. 紧缩数据存储容量,减少存储空间
  2. 可以提高数据传输的速度,减少带宽占用量,提高通讯效率
  3. 对数据的一种加密保护,增强数据在传输过程中的安全性

三、怎样实现文件压缩

实现压缩的方式,大体上主要分为两类:有损压缩和无损压缩。
无损压缩:简单来将,就是压缩之后的文件经过还原后与源文件相同。常用于对文件的压缩
有损压缩:压缩过程中损失一定的信息,常用于图片或视频的压缩,有损压缩的压缩比率要比无损压缩高。
而对于文件的压缩,常用的方式有:
①专有名词采用的固定短语
②缩短文件中重复的数据
③给文件中每个字节找一个更短的编码
其中,给文件中每个字节找一个更短的编码这种方式较为常用。因为,文件中的数据在磁盘中都是以字节的方式来进行存储的,1字节=8比特位,可以给每个字节找一个更短的比特位编码来表示,这样就可以达到压缩(减小文件所占空间)的目的。
下图是使用等长的二进制编码来对源文件进行改写:

使用等长的编码来对文件进程改写,不一定能达到最好的压缩率。
但使用不等长的编码来改写文件的话,压缩率往往会更好,这种方式是使用出现频率高的字符采用更短的编码进行表示。
下图是使用了不等长编码方法:

四、创建哈夫曼树

基于哈夫曼编码的文件压缩方式就是使用不等长的编码来对原文件进行改写的。使用Huffman编码来进行文件压缩要经过四个步骤:
1.获取原文件中每个字节出现的次数
2.根据字节出现的频次信息构建Huffman树
3.获取Huffman编码
4.使用Huffman编码来改写文件

1.哈夫曼编码的方式

前面介绍用不等长编码的方式来对文件进行改写,但这些编码是怎么来的呢?为什么A:100 ,B:101, C:11, D:0
这中编码方式是通过哈夫曼树来进行编排的:

2.构建一棵哈夫曼树

知道了哈夫曼编码的方式之后,到底该如何构建一棵哈夫曼树呢?
从二叉树的根结点到二叉树中所有叶结点的路径长度与相应权值的乘积之和为该二叉树的带权路径长度WPL,将带权路径最小的二叉树称为Huffman树。
下图展示了哈夫曼树的构建方法:

关于具体哈夫曼树的创建代码,请参考:
(https://gitee.com/zhang-yucheng329/c-file-compression)

五、压缩

压缩过程需要要经过四个步骤:

1.获取原文件中每个字节出现的次数

对于获取文件中每个字节出现的次数,采用一个含有256个结构体类型的数组来保存较为方便。因为文件在磁盘中都是以字节的方式来进行存储的,可以用每个字符对应的ASCII码值来作为数组的下标,只需遍历文件中的每一个字节,遇到对应ASCII码的元素对结构体中的count进行++即可。
如下图,数组的下标与字符的ASCII码值一一对应:

2.根据字节出现的频次信息构建Huffman树

在构建哈夫曼树时,直接调用之前写过的创建树的方式即可,但需要注意一点:
哈夫曼树每个节点类型为结构体类型,因此在定义结构体的地方,需要对运算符(+,>,!=,==)进行重载,让编译器知道count之间的比较方式。
下图是创建Huffman树时需要注意的点:

3.获取Huffman编码

我们现在已经有了根据频次信息创建的Huffman树,现在只需要遍历Huffman树来获取编码即可。对于编码的获取方式,可以从根节点遍历到叶子节点来获取,也可以从叶子节点向上找到根节点获取。
这里采用第二种方式来获取编码,需要给节点中增加双亲的指针域,让Huffman树的表示方法为孩子双亲表示法。通过这种方式获取的编码最后需要进行逆置才是最终结果,下图是获取编码后的结果,与期望的编码相同:

4.使用Huffman编码来改写文件(压缩)

前三个步骤进行完之后,只需改写文件即可。还是需要循环读取文件内容,采取位操作按位或的方式将Huffman编码放置到比特位当中。
步骤:1.定义ch = 0,先让ch左移一位,再判断Huffman编码的每个比特位是否为1,为1则让ch与Huffman编码为1比特位进行或操作,这样就能将文件按照编码的方式改写。
最终改写结果:

关于具体文件压缩的代码,请参考:
(https://gitee.com/zhang-yucheng329/c-file-compression/tree/master/Compress)

六、解压缩

1.获取解压缩用到的信息

解压缩过程与压缩过程相反,需要将压缩文件还原成原文件。但使用解压缩进行还原是需要条件的,不能凭空还原,需要根据原文件信息进行。
因此,在压缩过程中就需要将解压缩需要的信息重新保存一下。解压缩还原有很多种方法,但每种方法的还原效率不一样,这里选择用哈夫曼树的方式来进行还原:通过原文件字节出现的频次信息,还原出一棵哈夫曼树,再从根节点遍历,读取压缩数据,当读到0往左子树走,读到1往右子树走,直到走到叶子节点的位置即还原了原数据,再回到根节点循环遍历压缩数据。
在解压缩过程中用到的信息:
1.原文件后缀
2.统计频次信息的总行数(方便对数据进行操作)
3.获取原文件字节出现的频次信息
4.压缩数据
往文件中写入信息后:

2.恢复哈夫曼树

有了这些信息,就可以对哈夫曼树进行恢复,继续进行解压缩的过程了,恢复哈夫曼树的过程相对简单,基于之前写过的构建哈夫曼树的方法,只需对文件中压缩信息做相对应的处理

3.恢复原文件(解压缩)

解压缩过程就是:根据压缩数据来遍历恢复的哈夫曼树,压缩数据为1就往右子树走,为0就往左子树走,知道走到叶子节点。通过以上所有步骤就能够完成压缩与解压缩的所有过程了。
这里还有一个小问题,压缩方法不能处理文件中的汉字,因为汉字是采用UTF-8编码进行编排的,它的编码不在ASCII码表中。因此需要将所有的char类型改变为unsigned char类型!!!
下面为原文件与解压缩之后的结果:

关于具体解压缩的代码(最终代码),请参考:
(https://gitee.com/zhang-yucheng329/c-file-compression)

总结

以上就是今天要讲的内容,本文简单介绍了基于哈夫曼编码的文件压缩方法,我收获很多。在写代码途中,不免遇到很多bug调试半天还解决不了,但最终还是解决了出来,这也是写代码必经的一个过程。
以下是我总结完成过程中注意的一些问题:
①创建哈夫曼树时,使用优先级队列来保存字符出现的频次信息时,优先级队列的比较方式需要自己进行给出,使用仿函数的方法让比较方式为每个节点中的权值
②在使用结构体来创建哈夫曼树时,需要对+,>,==,!=,进行重载,重载的目的:让编译器知道权值中的count之间的比较方式
③在构建哈夫曼树时,发现其他节点构建正确,但是值域为1的节点不是叶子节点,是因为数组中还存放着许多字符出现次数为0的节点,需要进行过滤,设置第三个参数invalid来过滤权值为0的节点
④再次读取文件时,需要将文件指针的位置重置到文件头部,使用fseek函数或者rewind函数
⑤在解压缩时,不一定是8个比特位都需要解压缩,因此需要增加判定条件,只要解压缩后的字节数与原文件相等就停止解压缩
⑥压缩和解压缩代码写完后,需要讲char类型改成unsigned char类型,因为原文件可能出现汉字,汉字对应的是utf-8编码,不在ASCII码表中
⑦在测试多行数据压缩时,又出现了问题,原因是当读取到\n换行使,并没有将换行所在的数据GetLine,因此解压缩时数据少了一行。
⑧在进行大量数据测试时出现问题,发现解压缩一部分内容就停止了,部分数据丢失,但已经解压缩的部分内容与原文件一样。原因是解压缩文件是二进制文件(即压缩结果是二进制数字),二进制文件中可能会
出现-1(FF),当为-1时就默认读到了文件末尾就结束解压缩过程了。
改进方法是:
将所有打开文件(fopen)中文件的读写方式由"r",“w"改为二进制读写式"rb”“wb”
⑨经过测试,发现对不同的文件(文本文件,二进制文件),图片,视频都能够进行压缩,但哈夫曼编码的文件压缩对不同种类的压缩率是不同的。
对于txt/c/cpp类后缀的文本文件,压缩率较高在30%~50%
对于png/jpg类后缀的图片,压缩率一般在70%~90%
对于exe类后缀的可执行文件,压缩率较低在80%~90%
⑩在对文件进行多次压缩时,压缩结果的大小不是每次会减少,有一个限度。
同时,哈夫曼编码的压缩方法也是可能会出现压缩结果变大的可能性。当文件中字节的种类偏多,并且字节出现的次数比较平均的情况下,压缩效率就会变差,因为统计字节出现的频次信息时,各个字节出现的次数差不多,构建出来的哈夫曼树就接近平衡二叉树,效果就会不理想。
当然,也会出现压缩后文件变大的情况:当哈夫曼编码的平均长度大于8字节时,压缩文件就会变大

基于哈夫曼编码的文件压缩相关推荐

  1. 基于哈夫曼编码对文件进行压缩和解压缩(详细讲解)

    基于哈夫曼编码对文件进行压缩和解压缩(详细讲解) 本文对应c++代码实现链接 一.背景 利用特定的算法来压缩数据的工具,压缩后生成的文件称为压缩包.如果想使用其中的数据,就得用压缩软件对数据进行解压. ...

  2. 基于哈夫曼算法的文件压缩软件

    数据结构课设(一) 作业要求 1.设计并实现一个使用哈夫曼算法对文件进行压缩的工具软件. 2.通过命令行参数指定操作模式(压缩/解压).源文件名.目标文件名. 3.压缩操作将源文件按字节读入并统计字节 ...

  3. 哈夫曼编码与文件压缩

    一:哈夫曼树与哈夫曼编码 大家知道,文件压缩的原理么? 假如我们有一个文件,文件当中仅有 A.B.C.D.E 五种字符,这五种字符出现的频率分别为 5次.4次.3次.2次.1次. 我们知道每个英文字母 ...

  4. 使用哈夫曼编码实现文件压缩__win10,c++

    系统:win10 工具:vc6.0 //我加了个计时,用int存储字符总数 //因此增加一个限制:文件不可大于2GB #include<iostream> #include<time ...

  5. 使用哈夫曼编码进行文件压缩

    给你一个图片文件,要求对其进行无损压缩, 看看压缩效果如何. 思路:读取文件-> 得到赫夫曼编码表 -> 完成压缩 将前面压缩的文件,重新恢复成原来的文件. 思路:读取压缩文件(数据和赫夫 ...

  6. 基于哈夫曼编码完成的文件压缩及解压

    这几天在较为认真的研究基于哈夫曼编码的文件压缩及解压,费了点时间,在这分享一下: 这里用链式结构,非顺序表结构: 文件压缩: 1.获取文件信息(这里采用TXT格式文本): 2.压缩文件: 3.写配置文 ...

  7. 哈夫曼编码解压缩文件 - Java实现

    文章目录 前言 一.文件压缩 二.文件解压 结语 前言 不了解哈夫曼树的可以移步查看我的另一篇博客:哈夫曼树(最优二叉树) 使用哈夫曼编码压缩文件,其实就是将每个字符的哈夫曼编码得到,每8位转为一个字 ...

  8. 哈夫曼树实现文件压缩

    最近在学了哈夫曼树之后,作为练习,写了一个文件压缩的小项目: 在这里和大家分享一下: 主要实现思路: 利用哈夫曼树的特性对字符进行哈夫曼编码,其中运用到了最小堆:利用最小堆的特性,找出构造哈夫曼树的结 ...

  9. 哈夫曼编码实现文件的压缩和解压

    哈夫曼编码的概念 哈夫曼编码是基于哈夫曼树实现的一种文件压缩方式. 哈夫曼树:一种带权路径最短的最优二叉树,每个叶子结点都有它的权值,离根节点越近,权值越小(根节点权值为0,往下随深度增加依次加一), ...

  10. 基于哈夫曼编码对txt文档实现压缩处理 | 算法分析之贪心算法设计 C语言版

    声明:凡代码问题,欢迎在评论区沟通.承蒙指正,一起成长! 目录 一.实验内容与要求 二.概要设计 三.直接上代码 四.运行结果 一.实验内容与要求 内容:哈夫曼编码是广泛地用于数据文件压缩的十分有效的 ...

最新文章

  1. 一.jquery.datatables.js表格显示
  2. Redis概述与Redis集群(一)
  3. QT的QSetIterator类的使用
  4. android 音频合成_【Android工具】用手机测量噪声的工具软件,噪声仪分贝计,量化噪声声音工具...
  5. 云原生时代微服务的高可用架构设计
  6. mybatis mapper配置 bigint_Mybatis-Plus入门
  7. 像冠军一样创建报告! Reporting Services的提示和技巧
  8. PX4无人机配置4G空地多机组网系统
  9. 三大开源bi工具_Superset,基于web的开源BI工具,github三万star
  10. 小米笔记本pro充电测试软件,一款给人心理落差较大的笔记本--小米笔记本Pro测评...
  11. 09年全球IT企业互联网公司市值排行榜
  12. Linux驱动:电阻屏驱动分析
  13. dw网页制作教程百度云盘_详细的dw网页制作教程_dw中图片轮播
  14. 内核网络数据结构-SKB
  15. html5代码验证电话号码,这个我觉得挺重要的!
  16. laravel 上传图片
  17. ubuntu 1204 server xp 硬盘安装
  18. 2022国赛数学建模思路 - 案例:线性优化-粒子群算法
  19. 未来科技的五大发展趋势
  20. JS获取当前使用的浏览器名字以及版本号

热门文章

  1. 安卓模拟ibeacon_android iBeacon开发模拟实例
  2. 华为服务器忘记系统密码忘了,服务器忘记密码重置
  3. vscode格式化代码设置
  4. 算法竞赛进阶指南0x00基本算法 0x01位运算 例题起床困难综合征
  5. 【利用python3和微信接口给女朋友做个公众号推送】
  6. C语言编程之一个最优美的图案
  7. matlab 使用.m文件,matlab 编写M文件(函数)
  8. excel打开oracle,Oracle PLSQL读取(解析)Excel文档
  9. 手机上怎么打开md格式的文件_手机解压专家app下载
  10. 关于LM2596S-5.0电流声问题——输出电容选择