COMP9101 学习笔记 霍夫曼编码 The Huffman Code

本文为个人学习笔记
如果觉得写的不错欢迎点赞收藏交流
如有疑问和建议欢迎留言或者私信

1. 霍夫曼编码 (The Huffman Code)

1.1 怎么定义好的编码?

由于计算机处理二进制位序列,人们需要一种编码模式将文本处理成二进制位的长串,以英文为例,26个字母,空格和5种标点符号共32个符号需要编码,以二进制表示则需要5位编码( 2 5 = 32 2^5 = 32 25=32),比如00000代表字母a,00001代表字母b,11111代表“…”。每个符号的五位都是完全充分的,平均每一个符号需要用到5位编码,ASCII就是利用这种方式的编码模式(当然,不止32位)。
数据压缩领域的一个基础问题便是“如何减少每个字母的平均位数”。我们注意到在实际的应用中,有些符号和字母比如a,b,c,d的出现频率明显高于x,y这些符号,用同样的位数传递低频词是一种浪费,所以也许我们可以对高频符号使用更小的位数,以达到“减少字母平均位数”的目的。

可变长编码模式:莫尔斯码
莫尔斯码把每个字母转换成序列,分别对应0,1。对于频繁使用的字母使用短的位串进行编码,比如e 对应0,t 对应1,a对应01。
当然实际上,由于每个字母的位数不定,编码变得不确定,0既可以是字母e的编码,也可以是字母a的前缀码。所以实际上,莫尔斯码使用的是0,1,暂停 对字母进行编码。

前缀码: 解决前缀问题
设定映射函数 γ \gamma γ,对于不同的 x , y ∈ S x,y \in S x,yS, γ ( x ) \gamma(x) γ(x)不是 γ ( y ) \gamma(y) γ(y)的前缀(就是映射表中不存在谁是谁的前缀)。
例:
字母集合 S = { a , b , c , d , e } S=\{a,b,c,d,e\} S={a,b,c,d,e}, 映射函数 γ ( a ) = 11 , γ ( b ) = 01 , γ ( c ) = 001 , γ ( d ) = 10 , γ ( e ) = 000 \gamma(a) = 11, \gamma(b) = 01, \gamma(c) = 001, \gamma(d) = 10, \gamma(e) = 000 γ(a)=11,γ(b)=01,γ(c)=001,γ(d)=10,γ(e)=000, 串 cecab 被编码为0010000011101,从左往右解码:

  1. 0,00都不是字母, 001是c,解码第一个001为字母c,这是一个安全的决定(不存在谁是谁的前缀)
  2. 删掉001,继续读0000011101,重复步骤1

最优前缀码
对于每个字母 x ∈ S x \in S xS,总计存在n个字母, 存在频率 f x f_x fx,使得 ∑ x ∈ S f x = 1 \sum _{x\in S} f_x = 1 xSfx=1
我们有每个字母的平均二进制位数:
A B L ( γ ) = ∑ x ∈ S f x ∣ γ ( x ) ∣ ABL(\gamma) = \sum_{x \in S} f_x |\gamma(x)| ABL(γ)=xSfxγ(x)
很显然,达到ABL最小值的编码模式便是最优前缀码。

1.2 设计寻找最优前缀码的算法

蛮力搜索所有的可能的前缀码寻找到最优的前缀码实际上不太可行,所以我们选择描述一个贪心算法,可以有效地构造最优前缀码。
假设有一套前缀码 γ \gamma γ,我们用二叉树T表示它,树叶数等于字母表S的大小,叶子代表S中的字母。以下的定理和命题就不证明了…
定理1: 从T构成的S的编码是一个前缀码
定理2: 与最优前缀码对应的二叉树T是满的
问题变成对于所有叶子x(也是所有字母):
A B L ( T ) = ∑ x ∈ S f x × d e p t h T ( x ) ABL(T) = \sum_{x \in S}f_x\times depth_T(x) ABL(T)=xSfx×depthT(x)

我们现在假设有一颗树 T ∗ T^* T,对应最优前缀码的结构,但是没有标记树叶。我们有如下定理:

定理4: 存在一个与树 T ∗ T^* T对应的最优前缀码,其中最低频率的两个字母被指定为树叶,这两片树叶是兄弟。

所以假设最低频率的两个字母为y’, z’, 定理4告诉我们要将他们两作为同一父节点下的兄弟树叶,这个父亲节点是元字母x’,频率为y’, z’之和,此时直接提出算法(Huffman算法):

  1. 构建元字母x’, f x = f y + f z f_x = f_y + f_z fx=fy+fz,删除y’, z’,构建新的字母表S‘
  2. 对树T‘构建关于S‘的前缀码 γ ′ \gamma ' γ
    从T’开始,拿掉标记为x’的树叶并在下面加上y’,x’的孩子

范例
S = ( a , b , c , d , e ) S = (a,b,c,d,e) S=(a,b,c,d,e) 且频率 f = ( 0.32 , 0.25 , 0.20 , 0.18 , 0.05 ) f = (0.32, 0.25, 0.20, 0.18, 0.05) f=(0.32,0.25,0.20,0.18,0.05)

  1. 频率最低两个数字 d, e,合并成新的元字母 < d , e > <d,e> <d,e>,构建新的字母表 S ′ = ( a , b , c , < d , e > ) S' = ( a, b, c, <d,e>) S=(a,b,c,<d,e>)对应频率 f ′ = ( 0.32 , 0.25 , 0.20 , 0.23 ) f' = (0.32, 0.25, 0.20, 0.23) f=(0.32,0.25,0.20,0.23)
  2. 频率最低两个数字 c, <d,e>,合并成新的元字母 < c , d , e > <c,d,e> <c,d,e>,构建新的字母表 S ′ ′ = ( a , b , < c , d , e > ) S'' = ( a, b, <c,d,e>) S=(a,b,<c,d,e>)对应频率 f ′ ′ = ( 0.32 , 0.25 , 0.43 ) f'' = (0.32, 0.25, 0.43) f=(0.32,0.25,0.43)

Huffman算法下的贪心规则是:合并最小频率的字母,我们并不知道这个规则为什么与整体的算法相适合,我们能做的只是保证他们是兄弟节点,这就足以产生一个少了一个字母的等价的新问题。

最优性的证明: 不想写了

运行时间: 除了最后一次,每次迭代只: 识别最低频率的两个字母并组合成新字母,假设字母表有n个字母,对n-1此迭代求和则是 O ( n 2 ) O(n^2) O(n2)。但是实际上Huffman是使用优先队列的理想环境,我们在堆实现的优先队列上维护字母表S,是的每次插入和最小元素的取出用 O ( l o g n ) O(logn) O(logn)时间,对于所有n次迭代,共有 O ( n l o g n ) O(nlogn) O(nlogn)时间

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值