GZIP压缩原理分析(30)——第五章 Deflate算法详解(五21) 动态哈夫曼编码分析(10)构建哈夫曼树(02)

*范式哈夫曼编码

使用静态哈夫曼编码的编码/解码双方同时拥有一张完全相同的码表,这张码表是事先规定好的,只要使用这种压缩方式并且使用这种压缩方式对应的静态哈夫曼编码,那么压缩方就照着码表压缩,解码方照着码表直接解压。就好比我们使用莫尔斯码通讯,双方在通讯之前就约定好使用莫尔斯码(什么时候约定的?可能是某次吃饭的时候,或者聊天的时候,或者一起喝酒的时候……),双方都有一张莫尔斯码表,通讯的时候,一方将明文编码成莫尔斯码发送出来,另一方收到信息对着码表解码即可。

动态哈夫曼编码和静态哈夫曼编码不同,没有固定的码表,编码过程依赖于被编码数据本身,被编码数据不同,编码结果就不同。就好比我们使用无线电通讯,通讯双方A和B事前都没有编码/解码用的码表,怎么办?A要根据自己要发送的实际内容决定码表,实际内容不同,码表也不同。此时要想让B把A发送的信息完整的解码,A就必须把自己编码的码表发送给B,这样B才能照着这张码表把收到的信息解码。A每次发送的信息不同,则每次发送给B的码表也就不同,为了通讯方便,A就在每次通讯的时候把码表和对应的信息一同发送给B,B拿着这次发来的码表直接解码这次发来的数据即可。这个过程其实就是动态哈夫曼编码的编码/解码过程,A相当于压缩,B相当于解压,在压缩的时候,要把码表记录在压缩结果中,解压方从压缩结果中把码表提取出来就可以解压了。

这就说到关键了,既然压缩要把码表记录在压缩结果中,那怎么记录,以什么方式记录?如果码表占用的空间较大,整个压缩结果比压缩之前还大,那压缩还有什么意义!我们知道,哈夫曼编码过程要使用到一棵二叉树,就是哈夫曼树,利用这棵树就可以得到最终的哈夫曼编码的码字。压缩并没有直接将码表记录在压缩结果中,而是把构建这棵动态哈夫曼树的信息记录在了码表,解压方通过这些信息在解压本地将动态哈夫曼树构建出来,再根据这棵树就可以得到解压所需的码表。只在压缩结果中记录构建哈夫曼树的信息,要比记录整个动态哈夫曼码表简单得多,而且整个压缩结果不至于太大。

这就又牵扯出另外一个问题:构建哈夫曼树的信息包括什么?前面预备知识部分我们已经说了压缩使用的哈夫曼编码和原始哈夫曼编码不同,压缩使用的哈夫曼编码被称为“范式哈夫曼编码”。注意范式哈夫曼编码的定义“……使用某些强制的约定,仅通过很少的数据便能重构出哈夫曼编码树的结构”,正是范式哈夫曼编码的这些强制约定,简化了我们记录构建哈夫曼树所需的信息,这也就是为什么压缩要使用范式哈夫曼编码而不是原始哈夫曼编码的原因。还记得预备知识中我们提到的那几条哈夫曼树的性质吗?没错,那几条性质就是压缩所用哈夫曼树的“强制约定”,只不过这些强制约定是以数学的形式表述的。简单来说,压缩使用的哈夫曼树是一棵不平衡树,树的右侧始终比左侧要深!如下图所示,

左侧的哈夫曼树很显然没有保证树的右侧始终比左侧深,所以不能给压缩使用;右侧的哈夫曼树能够保证这一点,所以可供压缩使用。

上图中的两棵哈夫曼树如果单纯从原始哈夫曼编码的角度来看,并没有什么本质区别。这两棵树每个对应的叶子节点的码字长度都相同(比如左边哈夫曼树的f叶子节点和右边哈夫曼树的f叶子节点,虽然哈夫曼树不同,但是叶子节点的码字长度是相同的),而且都是前缀码,不同的仅仅是某几个叶子节点的具体码字不同而已,但这点差别根本无关痛痒。当压缩强制规定哈夫曼树必须使用形如上图右侧的哈夫曼树时,只要确定每个叶子节点的深度(树深,或者说是码字长度),就可以按部就班地将这棵“范式”哈夫曼树构建出来了。具体构造过程后面介绍。

总结,我们使用范式哈夫曼树来完成压缩的哈夫曼编码;压缩结果通过记录构造哈夫曼树的信息来间接告诉解压方码表;构造树的信息就是叶子节点的深度(称树深或码字长度都行),而且为了尽量减小压缩结果尺寸,构造树的信息只有码字长度。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值