文件压缩与解压:哈夫曼编码

源代码下载(VS2008工程):

http://download.csdn.net/detail/stevenkylelee/3761759

 

先上图

 

 

  把要压缩或要解压的文件拖拽到窗口中即可。另存为编辑框是压缩或解压的输出路径。对于压缩来说,另存为路径是目标文件的路径加上一个.shc扩展名。对于解压来说,会去掉最后一个扩展名。

  压缩的核心其实就是用了哈夫曼编码原理。我封装了一个哈夫曼编码类,内部使用了一个哈夫曼树类。

 

  要对一个文件进行压缩,执行如下步骤:

  1.建立编码方案。第一遍扫描文件,统计这个文件中各种不同的字节出现的次数(256种),以这个次数作为权值,建立对应的哈夫曼树。然后取得每个不同字节对应的01编码序列。

  2.计算压缩后的大小,压缩率。需要再次扫描文件。由于我用内存文件映射的方式来做压缩,所以这一步必不可少,要先知道将要创建的压缩文件的大小。

  3.执行编码。执行编码的话,要把原先的压缩信息写入文件的头部。有一个长1024字节大小的表,这个表记录了原先压缩的文件的每种字节出现的次数。还有一个4字节的字段,这个字段记录了压缩文件最后一个字节使用的比特位数。为什么要记录最后一个字节使用的比特位数呢?比如:A 对应01序列,B对应001序列,那么AB压缩后是:01001。对于一个字节来说,是有8位的,01001只使用了5位,还有3位未使用。

  要对一个文件进行解压,执行如下步骤:

  1.读取压缩时写入的文件头,也就是解压信息。重建原先的哈夫曼树。设置一个哈夫曼树游走指针指向树根节点。

  2.文件遍历指针越过文件头,指向压缩数据起始位置,遍历到文件尾部。每遇到一字节,还需要遍历这个字节的所有位。从其最高位向下遍历,如果此位是0,那么哈夫曼树游走指针就游走左子树路径。如果此位是1,就游走右子树路径。每次在哈夫曼树中游走后,都要判断下,是否走到了叶子节点。如果走到了叶子节点,就说明找到了解压信息,取出对应的叶子节点的数据信息,写入解压文件,并设置哈夫曼树的游走指针重新指向树根节点。

  OK,以上是压缩和解压步骤的概括说明。再补充一些细节。

  怎么对文件进行编码的呢?比如说"A"这个字母,其对应的ASCII码值是65吧。65对应的字节二进制数是:1000001。同理,"B"对应的二进制数是:1000010。正常情况下,A和B在内存都占用了1字节,AB同占用2字节。

  如果我们的哈夫曼编码计算出:A对应的编码为:01,B对应的编码为001。那么AB在一起就应该是01001,才占用了一个字节的5位嘛。这样在原先的基础上就节省出了1字节零3位,当然,零头3位在没编码占用的情况下,是没用的。

  由于,各种01序列编码的长度都不一样,所以,有可能一个编码会被字节的大小隔开。我们知道的,一个字节是8位。假如A编码为00001,B编码为000001,那么AB在一起的编码就是:00001000001了。这样子,一个字节是装不下的,需要分2个字节来装,便是:00001000 001。第二个字节只用了3位,剩下5位没用。这时,你就需要设置一个规定了,是前一个字节的高位接上后一个字节的低位,还是前一个字节的低位接上后一个字节的高位。我的选择是后者,感觉比较直观一些。

 

你可能感兴趣的:(C/C++)