【项目】哈夫曼树的应用:文件压缩

在前几天写了哈夫曼树以及哈夫曼编码的博客:

http://blog.csdn.net/wenqiang1208/article/details/77261906

文件压缩

文件压缩的主要思想是利用哈夫曼编码来实现的,但是得到编码之前我们需要构建这棵树。那么利用什么来构建树呢?!这里,我们需要统计每个字符出现的次数,用次数来构建Huffman-Tree。假设我们现在有一个.txt的小文件,内容是”aaaabbbccd”。字符存在计算机中时以字节为单位的,因此我们需要将这些字符压缩成0、1表示的编码,0和1表示字节中的“位”,这样能大大降低文件的大小。

这里写图片描述

源文件的的大小10个字节,
压缩后一共19个比特位,不足1个字节后面补足0,一共3个字节。

为了实现文件压缩,需要对文件字符信息进行定义

字符信息结构体
包括字符,字符个数,以及字符压缩后的编码。

struct FileInfo
{
    FileInfo()
    : _count(0)
    {}
    /*FileInfo operator+(const FileInfo& FileInfoRight)//会改变原来的值
    {
    this->_count += FileInfoRight._count;
    return *this;
    }*/
    FileInfo operator+(const FileInfo& FileInfoRight)
    {
        FileInfo  temp(*this);
        temp._count += FileInfoRight._count;
        return temp;
    }
    bool operator <(const FileInfo& FileInfoRight)const
    {
        return _count < FileInfoRight._count;
    }
    bool operator >(const FileInfo& FileInfoRight)const
    {
        return _count > FileInfoRight._count;
    }
    bool operator != (const FileInfo& FileInfoRight)const
    {
        return _count != FileInfoRight._count;
    }
    std::string _strCode;//存放当前字符压缩后的编码
    unsigned char _ch;//当前字符
    size_t _count;//统计字符个数
};

对文件信息进行压缩时,需要在新文件中写入头部信息,因为进行解压时需要文件信息。

头部信息包括下面三个部分:
扩展名:(就是源文件的后缀名)
编码行数
编码行 (字符:字符个数)

实现文件压缩的步骤:
(1)打开文件,对文件字符信息进行统计。CountFileInfo函数
(2)根据字符出现的个数,构建哈夫曼树,后序遍历哈夫曼树获取字符编码。FillCode函数和_GenerateHuffmanCode函数
(3)进行文件压缩,写入新的文件中;
a、先把头部信息写入新文件的首部(因为进行解压时,需要用到信息)。WriteHead函数
b、遍历源文件,将每个字符的编码信息写入新文件中。CompressCore函数

文件解压

文件解压,根据文件压缩文件,进行还原源文件。
(1)先读取头部信息,重新构建哈夫曼树。
(2)根据字符编码信息,对哈夫曼树进行遍历,叶子结点信息就是字符信息。
(3)将叶子结点信息重新写入文件中。

文件解压时遇到的问题

(1)比如说“aaa”并没有构建哈夫曼树,那么并没有写入编码信息,

解决方法:直接写入字符信息,不需要转码

(2)压缩信息后面 补足的0,可能会被误读成压缩信息。

压缩以后的文件如果不够一个字节大小,会用0来代替空缺的比特位,这样带来的问题就是可能会多解压出字符。以上述的”aaaabbbccd”为例,压缩以后的编码为19比特位:00001111 11110110 100,计算机存储的最小单位为字节,因此这些编码会被存储为00001111 11110110 10000000,后边的五个0对我们来说就是多余的,如果不处理,就会多还原出5个a。

解决方法:给出一个charCount来统计所有字符串的个数,其实也就是根节点的值,每次还原出一个字符后,charCount就-1,直到charCount为0时说明所有字符都已经解压完成。

代码地址
https://github.com/WenQiangW/FileCompress

测试

这里写图片描述

使用BeyondCompared软件进行对比源文件和新还原的文件,看是否还原成功。

在huffman文件压缩下:
压缩一个1.2M左右的文件,能够到压缩0.9M左右,用时0.5秒左右。
压缩一个2.3M左右的文件,能够到压缩1.8M左右,用时0.8秒左右。
压缩一个8.3M左右的文件,能够到压缩6.7M左右,用时3秒。

综合实验: 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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值