采用Huffman编码进行数据压缩

问题

      利用哈夫曼编码将英文文献进行压缩
注:哈夫曼算法及原理见博客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?从而实现压缩文件的功能。


      这里通过c语言中的位操作符,左移和右移来定位到每一个bit上,从而对bit进行赋值,或读取每一个bit。代码如下:
	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 注:不需要积分哦

程序运行和结果:

      将所有文件放在同一个执行目录下,如下:
littleant
      运行程序之后结果为:
littleant
      运行结果如下:
littleant

总结

      压缩后文件helloCompressed.txt大小为4kB,而目标文件hello.txt的大小为7kB。并且解压之后文件helloUnziped.txt与目标文件一模一样。
      压缩率为近50%。

猜你喜欢

转载自blog.csdn.net/Little_ant_/article/details/114039327