哈夫曼编码时遇到的一些问题


    好久没写东西了。这些天都在编Huffman编码树,遇到一些问题,发现原来都是在坑自己。


首先是以下代码无法正常读取文本文件


      
 char c;


      ifstream fin("inputfile1.txt");


      cout<<"File inputfile1.txt:"<<endl;


      while(fin.get(c))


            cout<<c;



得到的第一个字符总不是那个文本文件的第一个字符,而后面的字符还是正确的


    郁闷ing。。。


后来拿去讨教某大神,发现是是编码的问题,(悲催,在写编码程序的时候遇到编码的问题。。)于是拿个例子小试一会,发现果真如此。下图是两个除了编码方式外,内容完全一样的文件,其中Hhh(U).txt表示UTF-8编码的,Hhh(A).txt表示ANSI编码的。



然后用这个代码来输出两个文件的内容,并用文件比较命令比较这两个文件


发现输出时不一样的。而且差别仅在于头部。


(如下图)

隐约觉得好像是两种编码方式的文件头部不一样,应该是作为文件类型的标志的。于是用UE分别打开这两个文件,进行二进制的对比,结果如下图:

我们发现UTF-8编码的文件头部多了三个字节的东西:EF BB BF查了一下,原来所有采用UTF-8格式编码的文件的文件头三个字节用16进制表示是EF BB BF,因此在读取UTF-8格式文件的时候,需要去掉这个文件头。而当你并不了解读取的文件是GBK格式还是UTF-8格式时,你就不得不通过这个文件头来判断了。


由此可以看出windows下的记事本已经把文件头去掉了,所以文本文件看起来是一样的,但是文件比较命令会对所有的二进制代码进行转换,在控制台输出。这给我一个启示,如果有的文件如果无法确定类型或者后缀名因为某些原因被篡改或者删除,可以通过文件头来判断文件类型。


再比较这几种编码方式,发现ANSI编码是没有文件头的,而且每个半角英文字符只用一个字节编码,Unicode编码文件头是FF FE,而且而且每个半角英文字符只用两个字节编码,而Unicode big endian 文件头是FE FF 00,每个半角英文字符用两个字节编码。UTF-8编码的文件头是EF BB BF,每个半角英文字符用一个字节表示。所以同样的一个文本文件,不同的编码方式,文件大小还是不一样的,而且作业的Huffman编码只能处理ANSI编码的半角英文字符,离真正的压缩程序还有一定距离。至于对一个任何格式的文件用Huffman编码怎么去压缩呢?所有文件都是一堆的二进制代码的,应该可以选取一定长度的二进制数作为一组,然后对这个用Huffman编码,最后一组二进制数可能长度短一点,所以,把最后一组二进制放到文件头的后面,文件正文的前面,然后就大致可以了。


解决了这个问题,编码什么的都没问题,拿了个几句话的东西去用Huffman编码压缩,发现没有BUG,于是头脑发热,把自己做过的英语作文放入一个文本文件里,大小19KB,然后压缩,等着看好戏。然后好戏来了。。。。一堆BUG,我把编码的长度上限调到了16位,但是发现编码后解码的东西跟原文件简直就是天壤之别,文件大小只有10KB,哎。。这个跟几句话的情况除了每个字符数量多了点还能有什么区别呢??没有本质区别呀。于是一直将文件缩小,最后发现了一个问题。半角的英文字符里混进了全角的符号,而且看起来几乎是一样的,调这个调了好久。。。最后将中文的,全角的干掉,编码终于可以了。其实这都怪自己平时写英语作文时不小心,把非半角的东西弄进去。


最后,Huffman编码的平均编码长度,再根据香农第一定律计算了一下最短编码长度,发现ASCII是等长编码,平均长度就是每一个编码的长度7,Huffman编码的平均编码长度是4.41185,理论上的最短编码长度为4.37922,已经相当接近。(这些数据是在十几篇英语作文里面的含空格,回车等一切标点的19053个字符,1019个互不相同的单词的数据基础上得出的。),这些数据充分反映了我平时写作文的特点。可以证明,Huffman编码树是最理想的编码树。
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值