基于huffman树的文件压缩项目

文件压缩我总以为很神奇,所以一直觉得这是一个神奇的东西,但碰上神奇的东西我总是想一探究竟,在经过一番探寻答案的过程中,才发现原来文件压缩并非神奇,仅仅是利用了编码的原理转换了原来的内容而已,哈哈,这就像魔术很神奇,但是当你了解到它背后的原理,你就觉得如此普通,所以无论遇到什么看似很难的事情,只要静下心来去研究它,你总会有豁然开朗的那一天,加油吧,少年~

下面让我们一起走进文件压缩的世界吧!

文件压缩

1 什么是文件压缩?
    通过某一种机制让文件变小,并且能够通过某种方式对其还原。
2 文件压缩分类?
    无损压缩:解压缩之后的文件与源文件相同
    有损压缩:解压缩之后的文件与源文件不同
3 为什么要对文件压缩?
    节省空间
4 如何实现?
    文件:ABBBCCCCCDDDDDDD--16
    文件中内容在磁盘中以字节流的方式进行存储---字节---8比特
 
【等长编码】    
    00--A   
    01--B    
    10--C
    11--D
    00010101 10101010 10111111 11111111  
    0x15     0xAA     0xBF     0xFF  

【不等长编码】【huffman编码】
    A: 100
    B: 101
    C: 11
    D: 0

压缩:用找到的编码重新改写文件
    
解压缩:压缩文件 + 字符编码


哈夫曼树:带权路径长度[WPL]最短的二叉树

 

文件压缩的原理其实就是:基于huffman树编码原理

 

原理就是这么简单,,,一个字符占一个字节,现在用二进制编码代替之后,一个字符只占三位,也就是说一个字节可以表示两三个字符,所以说一次压缩,就会节省很多字节,也就起到了压缩的作用。

 

这个项目中,我觉得很重要的三点在于:

创建huffman树【权值w1,w2,,,wn】:
1 先用权值创建n棵只有根节点的二叉树森林【意思是先创建n个节点】
【用到了priority_queue优先级队列】

2 选取根节点权值最小的二叉树构建新的二叉树【建小堆,新二叉树根节点权值为左右子树的根节点权值之和】
3 删除使用的两棵根节点权值较小的二叉树
4 将新创建的二叉树添加到二叉树森林中
接下来2-4循环继续,直到二叉树森林中只有一棵二叉树则Huffman树创建成

 

文件压缩过程:
    0 读取源文件,读取源文件中每个字符出现的次数
    1 以每个字符出现的次数作为权值,创建huffman树:小堆--优先级队列
    2 通过huffman树找每个字符对应的编码
    3 用每个字符的新编码重新对源文件进行改写【翻译的过程】

 

文件解压缩的过程:

1. 从压缩文件中获取源文件的后缀
2. 从压缩文件中获取字符次数的总行数
3. 获取每个字符出现的次数
4. 重建huffman树

5. 解压压缩数据

    a. 从压缩文件中读取一个字节的获取压缩数据ch
    b. 从根节点开始,按照ch的8个比特位信息从高到低遍历huffman树:
        该比特位是0,取当前节点的左孩子,否则取右孩子,直到遍历到叶子节点位置,该字符就被解析成功,将解压出的字符写入文件,如果在遍历huffman过程中,8个比特位已经比较完毕还没有到达叶子节点,从a开始执行
     c. 重复以上过程,直到所有的数据解析完毕。

 

详细代码见GitHub:https://github.com/xiaobaiyuan-bit/filecompress.git

 

接下来就是我在写代码当中碰到的一些BUG和错误,我将这些总结起来:

(1).刚开始写的时候测试发现如果压缩文件中出现了中文,程序就会崩溃,将错误定位到构建哈夫曼编码的函数处,最后发现是数组越界的错误,

因为如果只是字符,它的范围是-128~127,程序中使用char类型为数组下标(0~127),所以字符没有问题. 但是汉字的编码是两个字节,所以可能会出现越界,

解决方法就是将char类型强转为unsigned char,可表示范围为0~255.

 

(2)文件恢复的时候需要注意那些问题? 

有些特殊字符在处理需要注意一下,比如'\n',我的程序中Getline()函数就是读取一行字符,但是若是该字符本身就是一个'\n'呢? 这就非常的棘手了. 因为解压缩之后出现了乱码.

对于这个问题一定好好处理,读取压缩文件时若读到了'\n',则说明该字符就是'\n',应该继续读取它的次数.

 

好了,基本上就是这些了,总结一句,实践与理论相结合,才会有大进步~

 

 

 

 

 

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
综合实验: 1. 问题描述 利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。这要求在发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站编写一个哈夫曼码的编/译码系统。 2. 基本要求 一个完整的系统应具有以下功能: (1) I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼,并将它存于文件hfmTree中。 (2) E:编码(Encoding)。利用已建好的哈夫曼(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。 (3) D:译码(Decoding)。利用已建好的哈夫曼文件CodeFile中的代码进行译码,结果存入文件Textfile中。 (4) P:印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。 (5) T:印哈夫曼(Tree printing)。将已在内存中的哈夫曼以直观的方式(比如)显示在终端上,同时将此字符形式的哈夫曼写入文件TreePrint 中。 3. 测试数据 用下表给出的字符集和频度的实际统计数据建立哈夫曼,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FAVORITE”。 字符 A B C D E F G H I J K L M 频度 186 64 13 22 32 103 21 15 47 57 1 5 32 20 字符 N O P Q R S T U V W X Y Z 频度 57 63 15 1 48 51 80 23 8 18 1 16 1

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值