1.前缀编码
首先对于一个串可以用等长的二进制位表示,这样就叫做固定长度编码。如果可以用不等长的二进制位表示,则称之为可变长度编码。那么对于那些频度高的字符我们采用短二进制位编码,出现频度低的采用长二进制位编码的话,将会极大地减少编码长度,起到压缩数据的作用。
在一个编码方案中,没有一个编码是另外一个编码的前缀,则称这个编码方案为前缀编码。对前缀编码的解码很简单,因为没有一个码是其他编码的前缀,所以识别出第一个编码翻译为原码,再对后续的编码文件重复进行同样的操作。比如0,101,100就是一组前缀编码。00100101,就可以唯一的被识别为0,0,100,101。而不会产生二义。
引入前缀编码的话就是想用一组能唯一标识的编码来表示原数据,并且数据所占空间最小。
编码 | 等长编码 I | 不等长编码 II | 不等长编码 III |
---|---|---|---|
a | 000 | 0 | 0 |
b | 001 | 1 | 101 |
c | 010 | 10 | 100 |
d | 011 | 11 | 111 |
e | 100 | 101 | 1101 |
1.对于等长编码5个字符来说,就需要至少3位,因为22=4,23=8才够用,就会浪费很多空间。
2.对于不等长编码I,abcde编码后就是011011101,那么在解码的时候就会出现0,11,0,11,101或者0,11,0,1,11,0,1等等其他错误的序列。
3.然后就出现了不等长编码III,abcde编码后序列就是01011001111101,解码的时候0,101,100,111,1101还原abcde不会出现二义。
所以编码II就不是前缀编码,编码III是前缀编码。
总之就是[1]采用不等长的编码方式就是为了压缩。[2]利用前缀编码就是解决能否唯一标识的问题。
2.哈夫曼编码与哈夫曼树
哈夫曼编码就是由哈夫曼树顺理成章得到的,上面说到了想要利用短二进制位去表示出现频度较高的字符从而达到压缩的效果。
2.1 首先Huffman树就是带权路径最小的二叉树称之为哈夫曼树,也叫最优二叉树。它的叶结点都是带有权值的,带权路径就是从叶结点出发到达根节点的路径数权值,就是该叶结点的带权路径,哈夫曼树保证所有叶结点的带权路径和最小。
WPL=∑wi*li.
以下图为例,a结点的带权路径值就是451=45,b结点带权路径值就是13*3=39。
2.2 然后说哈夫曼树如何构造:
首先已知各个节点的权值,现在所期望的就是带权路径和最小。所以对于权值较大的结点我们肯定希望它的路径短。
对于所有节点,我们先把每一个节点都设为一个根节点,这样就形成了n颗只有根节点的树了。
然后把权值最小的两棵树结合到一起,生成一个新的根节点,把两棵树的权值和作为新的树的根节点的权值。
对于新的森林重复上一操作,直到整个森林只剩下一棵树的时候。
以上图为例:
1.首先已知abcdef的权值,a(45)、b(13)、c(12)、d(16)、e(9)、f(5)。然后找到权值最小的两棵树f和e构成一颗新树,权值为f+e=14。
2.对于新的森林找到权值最小的两棵树c和b构成一颗新的树,权值为c+b=25。
3.重复操作,直到得到上面的那棵树。
2.3对于构造好的哈夫曼树,令左子树编码为0,右子树编码为1(也可以相反)。从根结点出发到达叶结点就可以得到哈夫曼编码:
a:0
b:101
c:100
d:111
e:1101
f:1100
这样的话存储的位数就是WPL=1*45+3*13+3*12+3*16+4*9+4*5=224位。
而用等长编码的话,abcdef一共6个字符,至少需要3位(23=8),得到的二进制编码位数为3*(45+13+12+16+9+5)=300位。
这里共压缩了25%的数据,这就是哈夫曼编码的作用。哈夫曼树可以设计出总成都最短的二进制前缀编码。