文件压缩(哈夫曼树)

基于huffman压缩算法实现文件压缩项目

以字符串“aaaabbbccd”为例实现文件压缩。
(1)统计各字符出现个数
a:4
b:3
c:2
d:1
(2)利用各字符出现的次数作为权值构建huffman树
哈夫曼树又称为最优二叉树,是加权路径长度最短的二叉树。
构建规则:每次在给定数据中挑选出两个权值最小的数,分别作为左右孩子节点,构建一个父节点将两个孩子节点链接起来,父节点权值等于左右孩子权值之和,然后再将父节点放回存放数据的序列;重复过程,直到所有数据存放数中。下图以1,2,3,4四个数字为例构建哈夫曼树。右边为得到的huffman编码。
这里写图片描述
(3)进行压缩
压缩之前文件中存放的是“aaaabbbccd“一共10个字节;进行编码后每个字符可以使用一段二进制序列表示对应的编码,同样上图的编码,写入文件信息就是”0000(4个a)101010(3个b)111111(2个c)110(1个d),占19个比特位,所以占用3个字节,原文件中10个字符都是char型,所以占用10个字节,以此达到huffman树文件压缩的效果。
huffman压缩算法压缩率高的情况就是出现特别多的重复字符(如上图中的”a”),只有少数是别的字符。效率低的情况就是每个字符出现的次数基本相同。

注意点:
1)向文件中写入信息时,按照二进制读写方式写入;每次向内存写入一个字节;最后若不满一个字节,单独进行判断补0.
2)建立配置文件:在解压缩时,如果没有配置文件,那么文件中只有0101序列,根本不知道写的是什么;所以需要增加配置文件,在压缩文件的开头先记录出现的每个字符以及对应出现的次数,方便解压缩时重建huffman树。

(4)解压缩
拿着压缩文件进行读取并重新写入文件。

注意点:
1)先读取配置文件重新构建huffman; 2)压缩过程中最后的填充位导致数据冗余。
3)解压缩的过程就是拿着我们之前压缩文件中的信息进行重新构建huffman树,按照对应的编码翻译出对应的字符即可。
4)由压缩文件还原文件的时候如何知道压了多少字符呢?当压缩的时候最后一位补了0的在解压缩的时候可能会把这个补的位当成原字符的编码来处理。如何解决呢?一种想法是在统计字符出现的次数的时候设置一个变量,每读取一个字符该变量的值就+1,最后将该变量写进配置文件中;另外一种想法就是根据根节点的权值,由上例不难看出根节点权值中的_count就是字符出现的次数。

由上述步骤程序基本可以压缩少量字符并正确的还原了,那么如果时大文件或者是汉字,图片以及音频文件呢?
1)读取字符时如果使用EOF进行判断,可能会导致写入的内容不全。使用feof函数代替:feof是一个c语言函数,既可用以判断二进制文件又可用以判断文本文件。
2),汉字,图片,视频在内存中是以二进制形式存储,二进制写入就需要采用二进制读写方式,在open文件时,采用”rb”,”wb”选项。
3)统计字符出现次数应该用的类型是long long,解决大文件压缩和解压缩问题。
总结:
(1)当待压缩文件中出现来了中文,程序就会崩溃,最后发现是数组越界的错误,程序中使用char类型为数组下标(0~127),如果只是字符它的范围是-128~127,而汉字的编码是两个字节,因此需要将char类型强转为unsigned char,可表示范围为0~255
(2)特殊情况处理:当遇到\n,程序函数就是读取一行字符,但若字符本身末尾就含有’\n‘,需要特殊处理。读取配置文件时如果读到了’\n’,说明字符本身就是’\n’,应继续读取它的次数。

代码存放:[https://github.com/zjx150714/zipfile]
测试用例情况分析:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/zjx624bjh/article/details/81368672