算数编码 vs 哈夫曼编码
这其实是我想重点探讨的一个部分。在这里默认你已经懂哈夫曼编码,因为这是一种最基本的压缩编码,算法课都会讲。哈夫曼编码和算数编码都属于熵编码,仔细分析它们的原理,这两种编码是十分类似的,但也有微妙的不同之处,这也导致算数编码的压缩率通常比哈夫曼编码略高,这些我们都会加以探讨。

不过我们首先要了解什么是熵编码,熵是借用了物理上的一个概念,简单来说表示的是物质的无序度,混乱度。信息学里的熵表示数据的无序度,熵越高,则包含的信息越多。其实这个概念还是很抽象,举个最简单的例子,假如一段文字全是字母A,则它的熵就是0,因为根本没有任何变化。如果有一半A一半B,则它可以包含的信息就多了,熵也就高。如果有90%的A和10%的B,则熵比刚才的一半A一半B要低,因为大多数字母都是A。

熵编码就是根据数据中不同字符出现的概率,用不同长度的编码来表示不同字符。出现概率越高的字符,则用越短的编码表示;出现概率低的字符,可以用比较长的编码表示。这种思想在哈夫曼编码中其实已经很清晰地体现出来了。那么给定一段数据,用二进制表示,最少需要多少bit才能编码呢?或者说平均每个字符需要几个bit表示?其实这就是信息熵的概念,如果从数学上理论分析,香农天才地给出了如下公式:

H(x)=−∑i=1np(xi)log2p(xi)H(x)=-\sum^n_{i=1}p(x_i)log_2p(x_i) H(x)=−i=1∑n​p(xi​)log2​p(xi​)其中 p(xi)p (x_i)p(xi​) 表示每个字符出现的概率。logloglog对数计算的是每一个字符需要多少bit表示,对它们进行概率加权求和,可以理解为是求数学期望值,最后的结果即表示最少平均每个字符需要多少bit表示,即信息熵,它给出了编码率的极限。

算数编码和哈夫曼编码的比较

在这里我们不对信息熵和背后的理论做过多分析,只是为了帮助理解算数编码和哈夫曼编码的本质思想。为了比较这两种编码的异同点,我们首先回顾哈夫曼编码,例如给定一段数据,统计里面字符的出现次数,生成哈夫曼树,我们可以得到字符编码集:

Symbol Times Encoding
a 3 00
b 3 01
c 2 10
d 1 110
e 2 111


仔细观察编码所表示的小数,从0.0到0.111,其实就是构成了算数编码中的各个概率区间,并且概率越大,所用的bit数越少,区间则反而越大。如果用哈夫曼编码一段数据abcde,则得到:

00 01 10 110 111

如果点上小数点,把它也看成一个小数,其实和算数编码的形式很类似,不断地读入字符,找到它应该落在当前区间的哪一个子区间,整个编码过程形成一个不断收拢变小的区间。

由此我们可以看到这两种编码,或者说熵编码的本质。概率越小的字符,用更多的bit去表示,这反映到概率区间上就是,概率小的字符所对应的区间也小,因此这个区间的上下边际值的差值越小,为了唯一确定当前这个区间,则需要更多的数字去表示它。 我们仍以十进制来说明,例如大区间0.2到0.3,我们需要0.2来确定,一位足以表示;但如果是小的区间0.11112到0.11113,则需要0.11112才能确定这个区间,编码时就需要5位才能将这个字符确定。其实编码一个字符需要的bit数就等于 -log ( p ),这里是十进制,所以log应以10为底,在二进制下以2为底,也就是香农公式里的形式。

哈夫曼编码的不同之处就在于,它所划分出来的子区间并不是严格按照概率的大小等比例划分的。例如上面的d和e,概率其实是不同的,但却得到了相同的子区间大小0.125;再例如c,和d,e构成的子树,c应该比d,e的区间之和要小,但实际上它们是一样的都是0.25。我们可以将哈夫曼编码和算术编码在这个例子里的概率区间做个对比:

这说明哈夫曼编码可以看作是对算数编码的一种近似,它并不是完美地呈现原始数据中字符的概率分布。也正是因为这一点微小的偏差,使得哈夫曼编码的压缩率通常比算数编码略低一些。或者说,算数编码能更逼近香农给出的理论熵值。

为了更好地理解这一点,我们举一个最简单的例子,比如有一段数据,A出现的概率是0.8,B出现的概率是0.2,现在要编码数据:

AAA…AAABBB…BBB (800个A,200个B)

如果用哈夫曼编码,显然A会被编成0,B会被编成1,如果表示在概率区间上,则A是 [0, 0.5),B是 [0.5, 1)。为了编码800个A和200个B,哈夫曼会用到800个0,然后跟200个1:

0.000…000111…111 (800个0,200个1)

在编码800个A的过程中,如果我们试图去观察编码区间的变化,它是不断地以0.5进行指数递减,最后形成一个 [0, 0.5^800) 的编码区间,然后开始B的编码。

但是如果是算数编码呢?因为A的概率是0.8,所以算数编码会使用区间 [0, 0.8) 来编码A,800个A则会形成一个区间 [0, 0.8^800),显然这个区间比 [0, 0.5^800) 大得多,也就是说800个A,哈夫曼编码用了整整800个0,而算数编码只需要不到800个0,更少的bit数就能表示。

当然对B而言,哈夫曼编码的区间大小是0.5,算数编码是0.2,算数编码会用到更多的bit数,但因为B的出现概率比A小得多,总体而言,算术编码”牺牲“B而“照顾”A,最终平均需要的bit数就会比哈夫曼编码少。而哈夫曼编码,由于其算法的特点,只能“不合理”地使用0.5和0.5的概率分布。这样的结果是,出现概率很高的A,和出现概率低的B使用了相同的编码长度1。两者相比,显然算术编码能更好地实现熵编码的思想。

从另外一个角度来看,在哈夫曼编码下,整个bit流可以清晰地分割出原始字符串:

而在算数编码下,每一个字符并不是严格地对应整数个bit的,有些字符与字符之间的边界可能是模糊的,或者说是重叠的,所以它的压缩率会略高:

当然这样的解释并不完全严格,如果一定要究其原因,那必须从数学上进行证明,算数编码的区间分割是更接近于信息熵的结果的,这就不在本文的讨论范围了。在这里我只是试图用更直观地方式解释算数编码和哈夫曼编码之间微妙的区别,以及它们同属于熵编码的本质性原理。

总结
算数编码的讲解就到这里。说实话我非常喜欢这种编码以及它所蕴含的思想,那种触及了数学本质的美感。如果说哈夫曼编码只是直观地基于概率,优化了字符编码长度实现压缩,那么算术编码是真正地从信息熵的本质,展现了信息究竟是以怎样的形式进行无损压缩,以及它的极限是什么。在讨论算术编码时,总是要提及哈夫曼编码,并与之进行比较,我们必须认识到它们之间的关系,才能对熵编码有一个完整的理解。


转载自:https://segmentfault.com/a/1190000011561822

算数编码与哈夫曼编码的比较【转载】相关推荐

  1. 香农费诺编码 c语言实现,对于香农编码、费诺编码和哈夫曼编码,编码方法惟一的是()。...

    问题标题 对于香农编码.费诺编码和哈夫曼编码,编码方法惟一的是(). 2019-8-15来自ip:15.170.14.227的网友咨询 浏览量:533 手机版 问题补充: 题目类型:[填空题] 对于香 ...

  2. 霍夫曼树和霍夫曼编码以及霍夫曼编码的应用

    文章目录 霍夫曼树介绍 1.1霍夫曼树的定义 1.2霍夫曼树的几个概念 1.3构建霍夫曼树的过程 1.4代码实现霍夫曼树 霍夫曼编码介绍 什么是霍夫曼编码 通信领域的应用 字符串压缩 1.构造霍夫曼树 ...

  3. 【Android 内存优化】Android 原生 API 图片压缩原理 ( 哈夫曼编码开关 | 哈夫曼编码原理 | libjpeg-turbo 函数库 )

    文章目录 一. 哈夫曼编码开关 二. 哈夫曼编码原理 三. libjpeg-turbo 函数库 四. libjpeg-turbo 函数库下载 [Android 内存优化]图片文件压缩 ( Androi ...

  4. 信息论与编码_哈夫曼编码

    哈夫曼树 哈夫曼树(Huffman Tree)也是一种特殊的二叉树,这种树的所有叶子结点都带有权值,从中构造出带权路径长度最短的二叉树,即哈夫曼树. 哈夫曼树的定义 ​ 设二叉树具有n个带权值的叶子结 ...

  5. 算法导论——贪心算法:哈夫曼编码(霍夫曼编码)

    2019独角兽企业重金招聘Python工程师标准>>> package org.loda.greedy;import org.junit.Test; import org.loda. ...

  6. 信源编码的代码实现 (香农编码、费诺编码、哈夫曼编码、游程编码、算术编码)

    文章目录 香农编码 费诺编码 哈夫曼编码 C++版 C语言版 游程编码 算术编码 香农编码 (1) 将信源消息符号按其出现的概率大小依次排列 p1 ≥ p2 ≥ - ≥ pn (2) 确定满足下列不等 ...

  7. 2022P02014139杨智关于香农编码、哈夫曼编码和费诺编码的比较

    注:以下三种编码比较都是在二进制下讨论的,其它进制下的编码情况可以与二进制下的情况类比. 1香农编码 概念: 香农编码是是采用信源符号的累计概率分布函数来分配字码的.香农编码是根据香农第一定理直接得出 ...

  8. labview霍夫曼编码_香农编码与霍夫曼编码

    一.香农-范诺编码 香农-范诺(Shannon-Fano)编码的目的是产生具有最小冗余的码词(code word).其基本思想是产生编码长度可变的码词.码词长度可变指的是,被编码的一些消息的符号可以用 ...

  9. 20172311-哈夫曼编码测试

    20172311-哈夫曼编码测试 哈夫曼编码与哈夫曼树 哈夫曼树 哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树.所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根 ...

最新文章

  1. 笑傲江湖霍建华版电子相册
  2. [译] 这可能是 2018 年最好的一篇 PHP 性能测评(包含 5.6 到 7.2,以及 HHVM)
  3. 字符串操作:截取表单网址里的信息变成对象
  4. Jquery.tmpl
  5. 什么是思考?如何主动思考?
  6. 实时高清渲染:Shadows
  7. 使用FeedDemon整理RSS Feed
  8. 服务器项目描述,项目服务器 2010 SP2 的描述
  9. 高等组合学笔记(三): 间隔排列,投票问题,圈集排列组合与生成函数简介
  10. 纯CSS 毛玻璃效果
  11. vm虚拟机下ubuntu 联网方式
  12. java 里面耦合和解耦
  13. MySQL 主从复制类型及详解
  14. Mongodb 设置账号密码
  15. 抖音落地页跳转添加微信好友的方法
  16. Sothink.SWF.Decompiler.v4.5-SHOCK
  17. 德国光量子计算机,新型量子光源为光学量子计算机铺平道路
  18. ​Aqua Data Studio 22.2 Crack
  19. DeepLab大盘点 | 深入理解DeepLab系列语义分割网络
  20. 移除Selenium的浏览器window.navigator.webdriver等20多个指纹特征

热门文章

  1. 面试官系统精讲Java源码及大厂真题 - 40 打动面试官:线程池流程编排中的运用实战
  2. JavaScript缓存处理代码
  3. 解决小程序图片在开发者工具能显示,测试时真机不显示问题
  4. ubuntu18.04管理redis
  5. 【错误记录】 ERROR java.lang.NoClassDefFoundError
  6. springboot 远程调用shell脚本,环境为windows
  7. Yarn 报错:error Couldn‘t publish package: “https://registry.yarnpkg.com/ 。。。Forbidden“
  8. C#LeetCode刷题之#205-同构字符串(Isomorphic Strings)
  9. 跨域 cors 请求两次_请求两次的故事-CORS
  10. facebook 面试_我在Facebook接受了应届毕业生的面试。 这是我从设计中学到的东西。...