基于哈夫曼编码的任意文件压缩与解压

基于哈夫曼编码的任意文件压缩与解压
说明:
       本人是初学者,只是想分享下自己的心得,大侠勿笑。
       上学期刚学完数据结构,假期要做个课程设计,就是《基于哈夫曼编码的任意文件压缩与解压》,大家都知道哈夫曼树和哈夫曼编码是如何构造的,但是可能有些朋友不知道如何把哈夫曼编码变为真正的二进制文件(至少我们同班的同学也不是全部知道,而且网上搜过下,也找不到相关介绍),所以就想在此讲下自己的方法,至于正确与否,望大家指正!
     
      另外,这里主要讲的是哈夫曼编码构造出来后的事情,至于哈夫曼树和编码的构造,用的是严蔚敏的《数据结构》或李春葆的《数据结构教程》的方法。
       由于是直接从word中copy的,效果不太好,可以点击下载doc文件
      控制台源程序:在vc6,vc8中测试过,点击下载
      (程序写得不好,比较混乱,效率不高,建议用release,快好多的)
      MFC版演示程序:点击下载
1. 问题描述
将任意一个指定的文件进行哈夫曼编码,并以真正的二进制位生成一个二进制文件(压缩文件);反过来,可将一个压缩文件解码还原为原来的文件。
2. 数据结构描述:
     以下是哈夫曼树结点的结构:           哈夫曼树以数组形式保存,其元素个数是2n-1,

struct HTNode
{
    char data;    // 结点值
    int weight;   // 权值 ;
    int parent;   // 父结点下标
    int lchild;   // 左孩子下标
    int rchild;   // 右孩子下标
};
 
typedef char* HCode;
 
                                             其中n为叶子数。对应结点的哈夫曼编码
                                        用一个数组记录,该数组元素是指向字符的指针

 

 
 
 
 
 

 
举例:设{a,b,c,d,e,f,g,h} 其权值 w={5,29,7,8,14,23,3,11} 则:
a
5
9
-1
-1
b
29
14
-1
-1
c
7
10
-1
-1
d
8
10
-1
-1
e
14
12
-1
-1
f
23
13
-1
-1
g
3
3
-1
-1
h
11
11
-1
-1
 
8
11
1
7
 
15
12
3
4
 
19
13
8
9
 
29
14
5
10
 
42
15
6
11
 
58
15
2
12
 
100
0
13
14
a
0 1 1 0
b
1 0
c
1 1 1 0
d
1 1 1 1
e
1 1 0
f
0 0
g
0 1 1 1
h
0 1 0

           data              weight           parent                lchild            rchild
    
3. 主要算法描述:
其基本实现方法是,因为任意文件实际都是二进制编码的,所以对选定的任意文件以二进制方式读入,一次读入一定的长度如4096 bytes,然后对每一字节(一字节8 bit,所以刚好对应256个ASCII字符)进行统计,如此循换,这就统计出文件的个字符的权值了。
得出文件各字节的权值后,就可以构造对应哈夫曼的哈夫曼树,从而就可以构造出对应字符的哈夫曼编码了。每个字符的哈夫曼编码都知道了,那么文件的哈夫曼编码就可以求出了。
现在讲下怎样把编码转为真正的二进制,并写入文件。先从文件中一次读入一定长度如 4096 bytes,然后对每一字符逐一处理,读到一个字符,则找出它的编码,把字符的编码不够8 bit的,读入下一个字符,找其编码,取其适当的位补齐前面不够8 bit的编码,然后转换为对应Ascii字符,然后写入这个字符,超过8 bit就分开。写入后继续处理后面的字符。
 
 
举例如下:
 
已知:a: 1010 b: 00 c: 10000 d: 1001 e: 11 f: 10001 g: 01 h: 1001
如果其中的一段是::acdef 则处理如下:(注意同一颜色对应一个字符的编码)

a          c          d           e      f

1010 1000 0 1001   11 1 0001 0000
 
       超过8bit,断开                         补上四位        这样就得到三个字符,分别是:
ASCII 168 的字符  ASCII79 的字符 
ASCII 16 的字符

   

 
 
如上述,这样就把编码按真正的二进制编码处理,把 5个字符压为3个字符,注意到,正如上例,当读文件到达文件尾时,一般不能刚好凑够8 bit 所以需要补上0直到够8 bit。
而补上的 0的个数记录为补位数
有了这些,现在可以写入文件了,我的写入方式是这样的:
结点数
补位数
压缩后的文件的哈夫曼编码总长度
文件类型(后缀名)
哈夫曼树(叶子结点值和权值部分)
压缩后文件的哈夫曼编码(压缩文件主要部分)
文件压缩基本上完了,现在介绍下解压的方法:
可以看到,有了上表的信息,自然能方便的解压出原来的文件了。读出结点数就能知道哈夫曼树存入部分的总长,方便读出树哈夫曼树(子结点值和权值),就能由次些信息重新构造完整的哈夫曼树,和各结点的哈夫曼编码。解压时,读取一个字节( 8 bit)用一个函数转换为8个字符(用一个数组记录,其元素只是一个0或一个1),然后按哈夫曼树从顶向下查找,如果到达叶子结点,就读出该叶子结点的值,放入缓冲区中,如果不是,则继续找,如此重复,直到缓冲区满了,就写入到解压文件中,再循环以上过程,直到处理完所有数据。
 

你可能感兴趣的:(编程学习志)