【数据压缩】Huffman编码
1. 压缩编码概述
数据压缩在日常生活极为常见,平常所用到jpg、mp3均采用数据压缩(采用Huffman编码)以减少占用空间。编码\(C\)是指从字符空间\(A\)到码字表\(X\)的映射。数据压缩编码指编码后信息的长度较于原始信息要短。本文试图探讨Huffman编码是如何保证唯一可译性、如何压缩、以及压缩效率如何?
前缀码
前缀码的任意一码字均不为其他码字的前缀,此保证了编码的唯一可译性。比如码字表{0, 01, 11, 1},0为01的前缀,1为11的前缀;当遇到字符文本011100,是应分隔为01-11-0-0还是0-11-1-0-0等?若采用前缀码编码,码字表为{0, 10, 11},则字符文本011100可即时分隔为0-11-10-0可译,所以前缀码亦被称为即时码。同时,前缀码保证了编码的唯一可译性,即字符空间\(A\)到码字表\(X\)的映射为一一映射。本文探讨的Huffman编码即为前缀码。
根据码字长度,编码分为等长编码与变长编码。等长编码即字母表中所有码字的长度均相等,最为常见的是字长7位的ASCII码。变长编码则是码字的长度可能存在不相等。
前缀码可表示为叶子节点为码字的编码二叉树,如图所示。

期望编码长度
如上图所示的两种变长编码,哪一种编码压缩效率比较好?显然,若信息编码之后的长度越小,则编码的压缩效率越好。为此,我们引出刻画量度期望编码长度。
首先我们定义字符空间\(A = \lbrace a_1,a_2, \cdots ,a_n \rbrace\),即信息文本中有n个字符,且字符\(a_i\)的长度为\(l_i\),出现频率(即概率)为\(p_i\);则期望编码长度为
\[
L = \sum\limits_{i = 1}^n {p_i*l_i}
\]
若要期望编码长度\(L\)越小,学过数学的都知道,则高概率的码字字长应不长于低概率的码字字长,即满足
\[\forall i,j \ \ \ p_i \ge p_j \Leftrightarrow l_i \le l_j\]
最优编码
对于二元编码(01)的前缀码,满足McMillan-Kraft不等式
\[\sum\limits_{i = 1}^n {{2^{ - l_i}}} \le 1\]
具体的证明参看[3]。McMillan-Kraft不等式从整体上限制编码长度的下界。
如下图所示的前缀码即满足McMillan-Kraft不等式。

最优编码指期望编码长度最小的编码,求解最优编码等价于数学问题:
\begin{align}
& \min \sum\limits_{i = 1}^n {{p_i}*{l_i}} \cr
& s.t. \ \sum {{2^{ - {l_i}}}} \le 1 \label{eq:kraft}
\end{align}
运用拉格朗日乘子法,构造目标函数
\begin{equation}
J = \sum {p_i*l_i + \lambda (\sum {{2^{ - l_i}}} } )
\end{equation}
对\(l_i\)求偏导,
\[{{\partial J} \over {\partial l_i}} = p_i - \lambda {2^{ - l_i}}\ln 2\]
令偏导为0,得到
\[{2^{ - l_i}} = {{p_i} \over {\lambda \ln 2}}\]
将其代入McMillan-Kraft不等式\eqref{eq:kraft}中,得到\(\lambda = {1 \over {\ln 2}}\),最优编码的码字长度
\begin{equation}
l_i = - \log _{2}p_i
\end{equation}
最优编码的期望码字长度即为字符空间的熵:
\begin{equation}
\sum\limits_{i} {p_il_i = - \sum\limits_{i} {p_i \log p_i} } = H(A)
\end{equation}
由此,定义编码的冗余度(Redundancy of a code),表示编码的冗余描述:
\begin{equation}
\rho = L - H(A)
\end{equation}
可以证明,前缀码的编码长度满足不等式
\begin{equation}
H(A) \le L \le H(A) + 1
\end{equation}
因此,前缀码的冗余度满足\(0 \le \rho \le 1\)。
2. Huffman编码
Huffman编码采用小顶堆来优化编码二叉树的建立过程,确保低概率的码字字长不短于高概率的码字,具体编码过程如下:
- 将字符空间的字符以概率为关键值建立小顶堆;
- 依次取堆顶元素两次,将该两个字符合成一棵二叉树,根节点的关键值为两个字符的概率相加;然后将该新合成的二叉树做为节点插入到小顶堆中;
- 重复步骤2直至小顶堆中只有一个节点,此节点即为编码二叉树。
编码二叉树建立过程如图所示

此字符空间有9个字符,采用等长编码则需要\(4\) bit;Huffman编码的期望字长则为\(2.77\) bit;字符空间的熵为\(2.69\) bit;冗余度为\(2.77-2.69=0.08\) bit.
关于Huffman编码的Python实现,请参看[4]。
3. 参考资料
[1] DAVID A. HUFFMAN, A Method for the Construction of Minimum-Redundancy Codes.
[2] Bernd Girod, EE398A Image and Video Compression.
[3] Cover T M, Thomas J A, Elements of Information Theory, 2nd edition[J].
[4] rosettacode, Huffman_coding#Python.
【数据压缩】Huffman编码的更多相关文章
- Huffman 编码压缩算法
前两天发布那个rsync算法后,想看看数据压缩的算法,知道一个经典的压缩算法Huffman算法.相信大家应该听说过 David Huffman 和他的压缩算法—— Huffman Code,一种通过字 ...
- [转载]Huffman编码压缩算法
转自http://coolshell.cn/articles/7459.html 前两天发布那个rsync算法后,想看看数据压缩的算法,知道一个经典的压缩算法Huffman算法.相信大家应该听说过 D ...
- [老文章搬家] 关于 Huffman 编码
按:去年接手一个项目,涉及到一个一个叫做Mxpeg的非主流视频编码格式,编解码器是厂商以源代码形式提供的,但是可能代码写的不算健壮,以至于我们tcp直连设备很正常,但是经过一个UDP数据分发服务器之后 ...
- Huffman编码
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <cstri ...
- 优先队列求解Huffman编码 c++
优先队列小析 优先队列的模板: template <class T, class Container = vector<T>,class Compare = less< ...
- Huffman编码实现电文的转码与译码
//first thing:thanks to my teacher---chenrong Dalian Maritime university /* 构造Huffman Tree思路: ( ...
- huffman 编码
huffman压缩是一种压缩算法,其中经典的部分就是根据字符出现的频率建立huffman树,然后根据huffman树的构建结果标示每个字符.huffman编码也称为前缀编码,就是每个字符的表示形式不是 ...
- 基于二叉树和数组实现限制长度的最优Huffman编码
具体介绍详见上篇博客:基于二叉树和双向链表实现限制长度的最优Huffman编码 基于数组和基于链表的实现方式在效率上有明显区别: 编码256个符号,符号权重为1...256,限制长度为16,循环编码1 ...
- uvalive 2088 - Entropy(huffman编码)
题目连接:2088 - Entropy 题目大意:给出一个字符串, 包括A~Z和_, 现在要根据字符出现的频率为他们进行编码,要求编码后字节最小, 然后输出字符均为8字节表示时的总字节数, 以及最小的 ...
随机推荐
- MVC4 学习备忘
WebConfig文件里添加数据库链接字符: <add name="MovieDBContext(可以自己取字符串名字)" connectionString="Da ...
- Replication的犄角旮旯(四)--关于事务复制的监控
<Replication的犄角旮旯>系列导读 Replication的犄角旮旯(一)--变更订阅端表名的应用场景 Replication的犄角旮旯(二)--寻找订阅端丢失的记录 Repli ...
- WPF,Silverlight与XAML读书笔记第四十七 - Silverlight与浏览器
说明:本系列基本上是<WPF揭秘>的读书笔记.在结构安排与文章内容上参照<WPF揭秘>的编排,对内容进行了总结并加入一些个人理解. 这部分内容主要介绍Silverlight与浏 ...
- 作业三:PSP耗时
请同学们参照教材<构建之法>2.3节表2-4 PSP2.1汇报自己在完成四则运算编程时候的时间分布,发布到博客上. 个人项目耗时情况分析 PSP Personal Software Pro ...
- sourcesafe.light 开源项目启动
sourcesafe.light 源于一个2D独立砖块沙盒游戏. 在这个游戏的设计中碰到了一个瓶颈:这个游戏想把玩家变成一个个neo,在矩阵世界中没有什么不可以修改. 这个游戏要跨平台,玩家的修改操作 ...
- Unity3D热更新全书-脚本(一) 初识脚本
开篇之前还是要先说明,这是一份给经验并不丰富的程序员阅读的文字. 有需求.有疑惑,往下看. 第一个问题什么是脚本?程序和脚本如何区分?我们给Unity编写的组件是程序还是脚本? 这些问题本文无意去解答 ...
- GLFW初体验
GLFW - 很遗憾,没有找到FW的确切含义,Wiki上没有,GLFW主页也没有.猜测F表示for,W表示Window GLFW是干啥用的? 一个轻量级的,开源的,跨平台的library.支持Open ...
- 12小时包你学会基于ReactMix框架的ReactNativeApp开发(二)基于Css+HTML写第一个app页面
上一篇文章,大家对于ReactMix(https://github.com/xueduany/react-mix)框架有了一个基本认识,知道我们是一个语法糖,帮助大家基于一套代码,所有平台都能跑.那么 ...
- js笔记——理解js中的call及apply
call及apply在js里经常碰得到,但一直感觉很陌生,不能熟练使用.怎样才能熟练应用呢? 为什么存在call和apply? 在javascript OOP中,我们经常会这样定义: function ...
- fir.im Weekly - 做一款 App 需要考虑什么
开发 App 是一个痛并快乐的旅程.工具越来越多,成本也越来越低,那么在开发之前需要考虑些什么?limboy 总结了一些经验和反思--做一个 App 前需要考虑的几件事,参考一下为你的 App 多留点 ...