目录
- 文件压缩
- 压缩本质
- huffman树
- huffman树的构建
- Huffman编码的压缩过程
- 获取Huffman编码
- 构建压缩信息
- Huffman编码的解压缩过程
- 解压压缩的数据
- 写压缩函数的注意事项
- 文件指针移动到头
- 测试过程
- 对文本文件进行压缩
- 纯英文文本测试
- 中文文本测试
- 中英文文本测试
- 对图片进行压缩解压缩
文件压缩
文件压缩可以简单理解为在不丢失有用信息的前提下,缩减数据量已达到压缩的效果。
压缩本质
1.专有名词采用的固定短语
比如:我们常把清华大学北京大学称为清北,这样的就是专有名词压缩。
2.缩短文件中重复的短语,即将重复的内容替换成更短的<距离,长度>对。
举个栗子:kiloluoshuabcxyzkiloxiaohengkiloluoshuabcdefg
替换后为kiloluoshuxyz<16,4>xiaoheng<28,10>abcdefg
3.给文件中每个字节找一个更短的编码,这种方式就是huffman编码的压缩原理
比如文件中存放的数据为: ABCDBBCCDDCCDDDD
我们可以采用对每个字符都替换成编码来表示
采用动态不等长编码表示即按出现次数,出现频率低的用更长的编码表示,出现频率高的用短的编码表示。
由此可以得到:
采用静态等长编码的压缩:00011011 01011010 11111010 11111111
采用动态不等长压缩: 100101110 10110111 11001111 0000
huffman树
从二叉树的根节点到二叉树所有叶节点的路径长度与相应权值的乘积之和为该二叉树的带权路径长度,带权路径最小的二叉树为Huffman树。
这棵树的带权路径为:13+33+52+71 = 29
huffman树的构建
1.将给定的N个权值W ={W1,W2…}构造N棵只有根节点的二叉树森林F = {T1,T2…}(我们这将统计次数放入节点中),每棵二叉树只有一个带权值W的根节点,无左右子树。
2.循环操作,直到只剩下一棵二叉树
a.在F中选取两棵根节点权值最小的二叉树作为左右子树构造一棵新的二叉树,新的根节点权值为其左右子树权值之和。
b.在F中删除这两棵二叉树
c.把二叉树加入到F中
Huffman编码的压缩过程
1.统计源文件中每个节点出现的次数
2.采用字节频次来获取Huffman编码
3.获取每个字节的Huffman编码
4.构建编码信息
5.用得到的编码对源文件中的每个字节进行改写
获取Huffman编码
有没有一种情况是如果不等长编码中出现一个编码是另一个编码的前缀呢?
这种情况是不可能出现的,因为在构建huffman树的时候出现次数只能是叶节点的位置。
构建压缩信息
因为我们创建压缩文件也要想办法把它恢复,所以节点中不仅要存放压缩后的数据还要保存对应的信息。
Huffman编码的解压缩过程
1.从压缩文件中获取源文件的后缀
2.从压缩文件中获取字符次数的总行数
3.获取每个字符出现的次数
4.重构huffman树
5.解压压缩的数据
解压压缩的数据
1.从压缩文件中读取一个字节的压缩数据ch
2.从根节点开始,按照8个比特位从高到低遍历huffman树,循环操作
写压缩函数的注意事项
文件指针移动到头
我在读取文件操作中读取了两次,文件指针在读取一次之后到了文件尾导致第二次读取不到数据,所以这里还要对文件指针进行处理。在第二次读取文件之前采用fseek(fIn, 0, SEEK_SET)将指针移到文件起始位置。
测试过程
对文本文件进行压缩
做完项目还要对项目进行测试,下面是我做的几个测试,来看看压缩解压有没有什么问题以及压缩率。
纯英文文本测试
我导入了一篇纯英文文档,可以看到huffman的压缩率在我这个测试中可以达到57%,当然中依靠huffman编码的压缩是达不到最好的效果的,还是需要再运用别的压缩算法来完善这个项目。
中文文本测试
我导入了一篇纯中文文档,可以看到Huffman压缩对文件大小也是有所减少的。
中英文文本测试
对图片进行压缩解压缩
对图片文件进行压缩来看看是否能还原
图片压缩的效果不明显但是能压缩和还原说明能支持不同格式文件的压缩。
项目代码上传置Gitee,源码链接:https://gitee.com/kilokeycode/CSDN-code/commit/2230452505e2c7c3be3f95e1227000994494a053