关于deflate树,能搜到的资料非常少,这个概念来自gzip的压缩算法,是由huffman树转变过来的。这里简单记录下deflate树的生成过程以及deflate编码。

假设以5 8 9 10 14 15,建立一颗huffman树,可以是这个样子的:

           /            \
27
/ \ / \ / \ / \

也可以交换任意结点的两棵子树

           /            \
34 27
/ \ / \ / \ / \

交换的过程虽然会改变叶子结点的huffman编码,但是,不会改变huffman树的带权路径和,也不会改变每个叶子结点的编码长度。基于这一点,我们可以做个更特殊的变换,每一层,让非叶子结点排在右边,叶子结点排在非叶子结点的左边。上面这棵树的变换之后如下:

           /            \

      /       \       /         \

                   /   \      /   \
                               
经过变换后,上面这颗树就称为deflate树。同样,deflate树虽然改变了结点的huffman编码,但是没有改变每个元素的编码长度。在gzip压缩中的语义就是没有改变压缩率。
上面的变化用语言表达起来不好理解,再用一个例子说明:
假设下面是一个huffman树:
                  A
/ \
B C
/ \ / \
D E F G
/ \ / \
G H I J
/ \
K L
/ \
M N 
转化为deflate之后,如下:
           A
/ \
B C
/ \ / \
D G F E
/ \ / \
I J H G
/ \
K L
/ \
M N
那么,转换为deflate树有什么好处呢?
这涉及到码表的记录。所谓的码表就是元素及其对应的编码。
先看下正常huffman编码下码表的记录
还是以5 8 9 10 14 15为集合,以下面这颗huffman树为例:
           /            \

      /       \       /         \

              /   \             /   \
                                
假设走左为0,走右为1,那么码表就是:
15          14              9             10            5            8
00          10             010         011           110        111
为了能够解码,我们必须把这个码表记录下来。
 
再看下转换为deflate树后,如何记录
上面这颗树转换后如下:
           /            \

      /       \       /         \

                    /   \      /   \
                                
假设还是走左为0,走右为1。转换后元素的编码改变了,码表应该如下:
15          14              9             10            5            8
00          10             100         101           110        111
虽然元素的编码变化了,但不要紧,只要我们记录如上这个码表,还是能把数据还原的。
前边说过,deflate虽然改变了编码,但是每个元素的编码长度是不变的,这个时候,可以只记录每个元素的编码长度,就可以在解码的时候把数据还原。现在,码表这么记录,每一层,从左往右记录叶子结点的编码长度,层次按从上到下。先记录第2层(根节点为第0层)的两个叶子,再记录第三次的4个叶子,码表如下:
15          14                 9         10            5            8
 2            2                 3           3             3            3
先别管如何根据这个码表解码,先对比下这两种记录法,会发现,下面这种码表记录要比上面的码表记录节省比特,2的二进制位10   ,  3的二进制位11   ,总的比特位6*2=12。
而上边的编码总长度为2+2+3+3+3+3=16(15、14的编码长度2,9、10、5、8的编码长度为3)。这并不是偶然,因为一个元素的编码的长度(10的编码长度为3)所占的二进制比特位(10的编码长度3,占二进制2位)肯定小于等于编码所占的长度(10的编码长度3)。
这就是记录码长的好处,为什么要这么计较这一丁点的比特呢,要知道,deflate树是用于压缩算法的,而且这样做并不复杂,何乐而不为?

现在再来说一下,有了这个码表如何解码,解码是编码的逆过程,所以,先看deflate树的编码

deflate树,编码方式为:

第n层的最左边的叶子结点的编码=((第n-1层的最左边的叶子结点的编码 )+  (第n-1层的叶子结点数))<< 1 。

第n层,后一个叶子结点的编码 = 前一个叶子结点的编码+1

还以下面这颗树为例:

           /            \

      /       \       /         \

                   /   \      /   \
                              
15的编码为00
那么9的编码 = (上一层最左边的叶子结点15的编码+上一层的叶子结点数2)<<1
                 =   (00 + 10)<<1
                 =    100
10的编码 = 9的编码+1 = 101
5的编码  = 10的编码+1 = 110
8的编码  = 5的编码+1 = 111
 
现在可以说解码过程了,码表先搬下来:
15          14                 9         10            5            8
 2            2                 3           3             3            3
由于这个码表的记录方法是每层叶子结点从左到右,并且层次从上到下的方式,而且,会发现,编码长度就是叶子所在的层次(假设根节点为第0层)。所以,第二层开始出现了第一个叶子结点,第一个叶子结点一定是一直往左的。那么根据编码规则15的编码就是00,14的编码是01,9的编码是(00+2)<<1 = 100...
 
这就是deflate树与deflate编码。事实上,在gzip中,deflate树的码表并不是这么记录,但deflate树的编码和解码思想是这样的。上面的码表了记录元素及其对应的码长,但在gzip中,为了更好压缩效果,并不会记录元素,而是直接记录元素的编码长度,用一个长度序列来表示码表。如果想了解其实现,应该去看看gzip的源码,gzip的源码非常精彩,极客思想无处不在,简直让人叹为观止。

deflate树与deflate编码的更多相关文章

  1. 树的Prufer 编码和最小生成树计数

      Prufer数列 Prufer数列是无根树的一种数列.在组合数学中,Prufer数列由有一个对于顶点标过号的树转化来的数列,点数为n的树转化来的Prufer数列长度为n-2.它可以通过简单的迭代方 ...

  2. huffman树即Huffma编码的实现

    自己写的Huffman树生成与Huffman编码实现 (实现了核心功能 ,打出了每个字符的huffman编码 其他的懒得实现了,有兴趣的朋友可以自己在我的基础增加功能 ) /* 原创文章 转载请附上原 ...

  3. 【转】ACM 2567 -- 树的Prufer编码

    本文介绍北京大学ACM网站2567号题目的解法.介绍部分基本翻译自网站上的题目介绍. 题目介绍:    给定一棵各节点编号为整数1,2,3...n的树(例如,无环连通图),其Prufer编码(Pruf ...

  4. BZOJ1005--[HNOI2008]明明的烦恼(树的prufer编码)

    1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 5768  Solved: 2253[Submit][Stat ...

  5. 树的prufer编码

    prufer是无根树的一种编码方式,一棵无根树和一个prufer编码唯一对应,也就是一棵树有唯一的prufer编码,而一个prufer编码对应一棵唯一的树. 第一部分:树编码成prufer序列. 树编 ...

  6. 数据结构(二十七)Huffman树和Huffman编码

    Huffman树是一种在编码技术方面得到广泛应用的二叉树,它也是一种最优二叉树. 一.霍夫曼树的基本概念 1.结点的路径和结点的路径长度:结点间的路径是指从一个结点到另一个结点所经历的结点和分支序列. ...

  7. Huffman树与Huffman编码

    1.Huffman树 今天复习Huffman树.依稀记得自己被Huffman树虐的经历.还记得是7月份,我刚开始看数据结构与算法,根本看不懂Huffman树的操作.后来我终于悟出了Huffman树是怎 ...

  8. 【51NOD1806】wangyurzee的树(Prufer编码,容斥原理,组合计数)

    题意:有n个点和m条限制,每条限制限制了一个点的度数不能为某个数. 求合法的树的个数模10^9+7 n<=10^6 m<=17 思路:WYZ作业 首先m<=17显然是2^m容斥 枚举 ...

  9. 简单的理解deflate算法

    简单的理解deflate算法 最近做压缩算法. 用到了deflate压缩算法,  找了很多资料,  这篇文章算是讲的比较易懂的, 这篇文章不长,但却浅显易懂, 基本上涵盖了我想要知道的所有要点. 翻译 ...

随机推荐

  1. amchart

    amchart能够根据提供的数据便捷的生成好看的图标,曾在项目中遇到使用falsh版以支持对js支持不好的低版本浏览器,但是现在官网上都是js版本的,flash版的文档都没有,搜索结果一般都是链接到博 ...

  2. 分割gbk中文出现乱码的问题解决

    近日遇到一个神奇的字“弢(tao)”. 具体的过程是这样的: $list = explode('|', 'abc弢|bc'); var_dump($list); 取得这个分割的结果. 和想象不同,结果 ...

  3. shopnc B2B2C商城 Nginx下开启伪静态

    B2B2C商城 Nginx下开启伪静态,伪静态开启后,对系统的SEO极为有利,可以最大限度让商城页面被搜索引擎抓取,但在实际安装中,很多客户在这块都会遇到各种各样的问题. 1. 编辑商城配置文件(da ...

  4. 更新项目经常使用的Linux命令

    在公司经常在服务器上更新项目,总结了自己经常使用的命令: 1.删除:rm -rf 文件名2.复制:copy 文件 目标地址3.压缩:zip -r 压缩后文件名 被压缩目录4.移动:move 文件 目标 ...

  5. Delphi 调用系统中的计算器、记事本、画图软件方法

    1.直接调用    前面uses加 ShellAPI ShellExecute(Handle, 'open', PChar('calc.exe'), nil, nil, SW_SHOW); 2.直接调 ...

  6. hdu4623:crime 数学优化dp

    鞍山热身赛的题,也是去年多校原题 题目大意: 求n个数的排列中满足相邻两个数互质的排列的数量并取模 当时的思路就是状压dp.. dp[i][state]  state用二进制记录某个数是否被取走,i ...

  7. FreeBSD简单配置SSH并用root远程登陆方法

    FreeBSD简单配置SSH并用root远程登陆方法 前言:最近下载了FreeBSD,在虚拟机上安装,第一步先要开启SSH服务,用终端putty软件可以实现在windows系统进行远程管理, 初级 = ...

  8. Codeforce 216 div2

    D 只要搞清楚一个性质:确定了当前最大和次大的位置,局面就唯一确定了; 根据这个性质设计dp,统计到达该局面的方法数即可. E 询问的要求是: 求有多少个区间至少覆盖了询问的点集中的一个; 转化成逆命 ...

  9. 深入浅出 消息队列 ActiveMQ

    http://blog.csdn.net/jwdstef/article/details/17380471

  10. Direct2D 简介

    Direct2D是什么? Direct2D是一套高性能的硬件加速API(代码运行在GPU),用于渲染几何图形,图片和文本,并且可以与Direct3D,GDI,GDI+交互. 什么程序员应该使用Dire ...