问题
利用哈夫曼编码将英文文献进行压缩
注:哈夫曼算法及原理见博客https://blog.csdn.net/Little_ant_/article/details/104246904在此不再赘述。
实验环境
VS2017 C++
程序组成
main.cpp 文件里调用具体的函数实现整体上的功能。
Huffm.h 文件中实现huffman算法的编码,以及译码到指定文件的功能。
Input.h 文件中统计文本信息,然后作为huffman算法的输入。
Output.h 文件中将目标文件通过huffman编码进行压缩。
hello.txt 文件为需要被压缩的文件,即目标文件 。
helloCompressed.txt 文件是被压缩之后得到的文件。
HelloUnziped.tx 文件是解压缩之后得到的文件。
实现思路
1, 先熟悉huffman算法的逻辑,并进行实现。(以前比较熟)
2, 构造huffman算法的输入,即统计文本信息,建立huffman树并完成huffman编码。
3, 通过huffman编码来将hello.txt中的字符转换为对应的编码,压缩文件为helloCompressed.txt
4, 通过译码算法来解压我们压缩过的文件,得到文件helloUnzipedtxt,并与目标文件hello.txt相对比。
具体的编码方式:对文本中每一个出现的字符进行频度统计,进行编码。
如何用二进制0/1表示字符 ‘0’ / ‘1’
通过Huffm.h将源文件进行编码,所得到的信息有,所有的字符数量 (int 型),字符种类数(int 型),huffman树(struct*)和huffman编码(char**)。假设对字符’a’所得到的huffman编码字符串为char* str=”0101” ,如何转化为二进制序列 0101?从而实现压缩文件的功能。
unsigned char ch1 = fgetc(streamin);//读源文件内容,逐字节来读取
char value = 0;
int pos = 0;
int resIndex;
int codeLen;
while (ch1 != EOF)
{
if (feof(streamin))
break;
resIndex = getHuffmanCode_index(data, ch1);
if (resIndex == -1)
return;
char* code = hc[resIndex];//每个字符的Huffman编码
codeLen = strlen(code);
for (int i = 0; i < codeLen; i++)//一个一个比特位来进行放
{
value <<= 1;
//先左移一位,如果code为1就进行下面的代码,把第一位变为1,为0就不处理
//循环进行,就会把哪一位为1就把那一位置为1
if (code[i] == '1')//得到二进制的1
{
value |= 1;//把原来为0的位置变为1,即就是写进1.
}
if (++pos == 8)//满8位写入文件
{
fputc(value, streamout);//把value写进去,里面存的8个位就是HuffmanCode
value = 0;//重置,循环写
pos = 0;
}
}
ch1 = fgetc(streamin);
}
ch1为源文件中读入的字符,code为该字符对应的huffman编码。value在此起到一个缓冲区的作用,一直在不停的左移,它是用来将字符 ‘1’ 转换为二进制 1的重点。假设编码序列为”0101111”,将其转换为二进制存储的过程如下:
初始:value 00000000
左移一位:value 00000000
判断序列的第一位,发现其为0,那就左移一位:value的值为00000000
判断序列的第二位,发现其为1,那就将上一步的value与00000001进行或操作,得到value值为:00000001 然后左移一位:00000010
判断序列的第三位,发现其为0,那就左移一位:value的值为00000100
判断序列的第四位,发现其为1,那就将上一步的value与00000001进行或操作,得到value值为:00000101 然后左移一位:00001010
判断序列的第五位,发现其为1,那就将上一步的value与00000001进行或操作,得到value值为:00001011 然后左移一位:00010110
判断序列的第六位,发现其为1,那就将上一步的value与00000001进行或操作,得到value值为:00010111 然后左移一位:00101110
判断序列的第七位,发现其为1,那就将上一步的value与00000001进行或操作,得到value值为:00101111 然后左移一位:01011110
从而我们将字符串”0101111”转换为二进制bit存储在字节value变量中,此时的value变量值为 01011110 ,前面7位是字符串,现在在等待下一字符串序列。
采用pos变量来记录左移的次数,如果左移8次,那就表示value的8个位已经存满了,就要将value输出到压缩文件helloCompressed.txt里面。清零pos,让value一直循环左移,直到将目标文件hello.txt中的字符全部读取。
解压缩过程同理。
源代码下载
https://download.csdn.net/download/Little_ant_/15452531 注:不需要积分哦
程序运行和结果:
将所有文件放在同一个执行目录下,如下:
运行程序之后结果为:
运行结果如下:
总结
压缩后文件helloCompressed.txt大小为4kB,而目标文件hello.txt的大小为7kB。并且解压之后文件helloUnziped.txt与目标文件一模一样。
压缩率为近50%。