http://www.cnblogs.com/zengzy/p/5156130.html

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

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

                  61/            \27              34/       \       /        \14       13     15        19/   \            /   \5     8          9    10

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

                 61/            \34              27                           /       \       /         \15      19      14        13/   \              /   \9   10             5    8

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

                  61/            \34              27                           /       \       /         \15        14    19         13/   \      /   \9   10     5    8

经过变换后,上面这颗树就称为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树为例:
                 61/            \34              27                           /       \       /         \15        19     14         13/   \             /   \9   10            5    8

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

假设还是走左为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

还以下面这颗树为例:

                 61/            \34              27                           /       \       /         \15        14    19         13/   \      /   \9   10     5    8

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的源码非常精彩,极客思想无处不在,简直让人叹为观止。

作者:zengzy 
出处: http://www.cnblogs.com/zengzy

分类:  数据结构与算法

deflate树与deflate编码相关推荐

  1. huffman树和huffman编码

    不知道为什么,我写的代码都是又臭又长. 直接上代码: #include <iostream> #include <cstdarg> using namespace std; c ...

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

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

  3. 数据结构实验三:Huffman树及Huffman编码的算法实现

    Exp03 Huffman树及Huffman编码的算法实现 Author: Maskros 实验目的 了解该树的应用实例,熟悉掌握Huffman树的构造方法及Huffman编码的应用, 了解Huffm ...

  4. 利用Huffman树进行文本编码解码的实现

    --------------------------------- 功能:利用Huffman树进行文本编码解码的实现 环境:WinXP,VC6.0 输入:C:\\in.txt 输出:C:\\out.d ...

  5. Huffman树与Huffman编码

    Huffman树与Huffman编码 问题描述 已知某系统在通信联络中只可能出现6种字符,其使用频度如下表所示: 根据Huffman编码原理,为6种字符设计一种Huffman编码方案. 算法分析与设计 ...

  6. 以太坊的MPT树,以及编码,leveldb存储

    声明:此为使用网上多处资料整理而成,由于很多地方内容相同,已经分不清哪里是原创 一.MPT树 1. Trie树 Trie,又称为字典树或者前缀树 (prefix tree),属于查找树的一种.它与平衡 ...

  7. 哈夫曼树 构造,编码 完整代码

    Haffman Tree 构造方法: 1.初始化每个叶子结点都是一棵树. 2.找最小权值的两棵树. 3.合并两树,生成新结点. 编码: 1.往左为1,右为0. 2.不等长编码. #include< ...

  8. C语言:哈夫曼树构造及编码(核心代码每一行都有注释)

    一.[实验目的及要求] 理解Huffman树的概念及其存储结构: 熟悉Huffman树的构造: 掌握Huffman树的编码方法. 二.[实验内容] 1.代码实现Huffman编码 2.请统计每个字符出 ...

  9. 【数据结构】基于c++的哈夫曼树构造、编码、译码算法实现

    创建哈夫曼树的描述: 数据结构: 数据的逻辑结构是树状结构:采用静态的三叉链表存放. 算法思想: 1.先把三叉链表中N个元素进行初始化,存放叶子节点,他们都没有孩子和双亲. 2.再初始化后n-1个非叶 ...

最新文章

  1. AIX忘记root密码后,重设密码步骤
  2. 如何让一套代码适配所有iOS设备尺寸?
  3. 全文索引 - Pomelo.EFCore.MySql
  4. jmeter进行性能测试_使用JMeter进行性能测试
  5. 前端学习(3262):js高级教程(5)数据变量和内存
  6. sql exist 优化查询时间
  7. GaussDB(DWS)应用实践丨负载管理与作业排队处理方法
  8. 测试过程中如何快速定位一个bug
  9. Selenium API-WebDriver 属性
  10. Win10 安装rational rose 7教程
  11. OpenWRT配置 -- 网络配置network文件
  12. 制作后台管理系统首页
  13. 深入解析Superdome 2:惠普关键业务平台再加强?
  14. 配置错误 访问被拒绝 解决方案
  15. Ubuntu解决文件带锁问题
  16. 走青甘西北环线,感受祖国的大、美、强
  17. WeGame聊天室采集
  18. STM32F0-DAY1
  19. vulnhub-FIRSTBLOOD1靶场
  20. 辩证唯物主义 历史唯物主义 第一章绪论 一 唯物主义和唯心主义

热门文章

  1. 线性模型之二:线性回归模型性能的评估(残差图、MSE与R2)
  2. Linux系统调用之lseek函数
  3. 读书笔记 -公司改造 和 紧迫感
  4. Spring系列之依赖注入的三种方式
  5. 长安链源码学习--提案(Proposer)(五)
  6. 宏定义函数和普通函数
  7. BZOJ 4544: 椭圆上的整点
  8. adb:failed to install app.apk Failure [INSTALL_FAILED_VERSION_DOWNGRADE: Package Verification Result
  9. 我是小交易所老板,我现在很慌
  10. int64_t 在 32 位环境下其实是 long long