该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
Huffman 编码简介
在一般的数据结构的书中树的那章后面著者一般都会介绍一下哈夫曼(HUFFMAN)树和哈夫曼编码哈夫曼编码是哈夫曼树的一个应用哈夫曼编码应用广泛如JPEG 中就应用了哈夫曼编码
为什么是二叉树
为什么压缩领域中的编码方法总和二叉树联系在一起呢原因非常简单回忆一下我们介绍过的前缀编码为了使用不固定的码长表示单个字符编码必须符合前缀编码的要求即较短的编码决不能是较长编码的前缀要构造符合这一要求的二进制编码体系二叉树是最理想的选择考察下面这棵二叉树
根(root)
0 | 1
+------+------+
0 | 1 0 | 1
+-----+-----+ +---+----+
| | | |
a | d e
0 | 1
+-----+-----+
| |
b c
要编码的字符总是出现在树叶上假定从根向树叶行走的过程中左转为0 右转为1,则一个字符的编码就是从根走到该字符所在树叶的路径正因为字符只能出现在树叶上任何一个字符的路径都不会是另一字符路径的前缀路径符合要求的前缀编码也就构造成功了
a - 00 b - 010 c - 011 d - 10 e - 11
Shannon-Fano 编码
进入Huffman 先生构造的神奇二叉树之前我们先来看一下它的前身由Claude Shannon和R.M.Fano 两人提出的Shannon-Fano 编码讨论之前我们假定要编码字符的出现概率已经由某一模型统计出来例如对下面这串出现了五种字符的信息( 40 个字符长):
cabcedeacacdeddaaabaababaaabbacdebaceada
五种字符的出现次数分别a - 16 b - 7 c - 6 d - 6 e - 5
Shannon-Fano 编码的核心仍然是构造二叉树构造的方式非常简单
1) 将给定符号按照其频率从大到小排序对上面的例子应该得到
a - 16
b - 7
c - 6
d - 6
e - 5
2) 将序列分成上下两部分使得上部频率总和尽可能接近下部频率总和我们有
a - 16
b - 7
-----------------
c - 6
d - 6
e - 5
3) 我们把第二步中划分出的上部作为二叉树的左子树记0 下部作为二叉树的右子树记
1
4) 分别对左右子树重复2 3 两步直到所有的符号都成为二叉树的树叶为止现在我们有如下
的二叉树
根(root)
0 | 1
+------+------+
0 | 1 0 | 1
+-----+-----+ +---+----+
| | | |
a b c |
0 | 1
+-----+-----+
| |
d e
于是我们得到了此信息的编码表
a - 00 b - 01 c - 10 d - 110 e - 111
可以将例子中的信息编码为
cabcedeacacdeddaaabaababaaabbacdebaceada
10 00 01 10 111 110 111 00 10 00 10 ......
码长共91 位考虑用ASCII 码表示上述信息需要8 * 40 = 240 位我们确实实现了数据压缩
哈夫曼树:
首先介绍什么是哈夫曼树哈夫曼树又称最优二叉树是一种带权路径长度最短的二叉树所谓树的带权路径长度就是树中所有的叶结点的权值乘上其到根结点的路径长度若根结点为0 层叶结点到根结点的路径长度为叶结点的层数树的带权路径长度记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln) N 个权值Wi(i=1,2,...n)构成一棵有N 个叶结点的二叉树相应的叶结点的路径长度为Li(i=1,2,...n) 可以证明哈夫曼树的WPL 是最小的哈夫曼在上世纪五十年代初就提出这种编码时根据字符出现的概率来构造平均长度最短的编码它是一种变长的编码在编码中若各码字长度严格按照码字所对应符号出现概率的大小的逆序排列则编码的平均长度是最小的注码字即为符号经哈夫曼编码后得到的编码其长度是因符号出现的概率而不同所以说哈夫曼编码是变长的编码
Huffman 编码
Huffman 编码构造二叉树的方法和Shannon-Fano 正好相反不是自上而下而是从树叶到树根生成二叉树现在我们仍然使用上面的例子来学习Huffman 编码方法
1) 将各个符号及其出现频率分别作为不同的小二叉树目前每棵树只有根节点
a(16) b(7) c(6) d(6) e(5)
2) 在1 中得到的树林里找出频率值最小的两棵树将他们分别作为左右子树连成一棵大一些的二叉树该二叉树的频率值为两棵子树频率值之和对上面的例子我们得到一个新的树林