数据结构(十四) -- Huffman树

本文将通过 Huffman 编码树的构造问题,介绍优先队列结构的具体应用。

二进制编码

通讯系统可以帮助人们将一段信息从发送端传送给接收端。最常见的信息形式是字符串,即由来自某一有限字符集Σ 的若干个字符组成的一个序列M = (x1, …, xn),xi∈Σ,1≤i≤n。在将M 加载至信道上并发送之前,首先需要对M 进行编码(Encoding)。通常采用的都是二进制编码,以英文字母集Σ = {A, B, C, …, Z}为例,若需要传送字符串“MAIN”,一种可行的编码方式就是:

e('N') = "00"
e('A') = "010"
e('I') = "011"
e('M') = "1"

若令每个字符分别对应于一匹叶子,则从根节点通往每匹叶子的路径,就对应于相应字符的二进制编码,这样的一棵树也称作二叉编码树。

二进制解码

反过来,根据这棵编码树也可以便捷地完成解码工作。

  • 从头开始扫描接收到的二进制信息流;

  • 从根节点开始,根据各比特位不断进入下一层节点;

  • 到达叶子节点后,输出其对应的字符;

  • 然后重新回到根节点,并继续扫描二进制流。

实际上,这一过程可以在接收过程中实时进行,而不必等到所有的比特位都到达之后才开始解码。

最优编码树

在实际的通讯系统中,信道的使用效率是个很重要的问题,这在很大程度上取决于编码算法本身的效率。很自然地,我们当然希望能够用尽可能少的比特位来表示字符串。那么,如何做到这一点呢?在什么情况下能够做到这一点呢?

先介绍一项编码效率的重要指标——平均编码长度

在二叉编码树中每个字符 c 的编码长度为对应的叶子的深度 depth(c)。

Σ 中各字符的编码长度总和除以字符集 Σ 就是单个字符的平均编码长度。

对于任一字符集Σ,若在所有的编码方式中,某一编码方式 e() 使得平均编码长度最短,则称 e() 为 Σ 的一种最优编码,与之对应的编码树称作 Σ 的一棵最优编码树。

我们注意到,对于同一字符集Σ,所有深度不超过|Σ|的编码树只有有限棵,因此其中的总编码长度最小者必然存在(尽管不见得唯一)。

如何找到最优编码树

首先需要更加深入地了解最优编码树的性质,在最优二叉编码树中:

  • (1) 每个内部节点的度数均为 2

  • (2) 各叶子之间的深度差不超过 1

推论:基于由 2 | Σ | -1 个节点构成的完全二叉树 T,将 Σ 中的字符任意分配给 T 的 | Σ | 匹叶子,即可得到 Σ 的一棵最优编码树。

这一推论也直接给出了一个构造最优编码树的算法。

带权编码

上面所介绍的最优编码树,在实际应用中的利用价值并不大。不难看出,只有当 Σ 中各个字符在信息串中出现的概率相等时,其最优性才有意义,遗憾的是,这一条件很难满足。

在实际应用中,Σ 中各字符的出现频率不仅很少相等或相近,而且往往相差悬殊。以英文信息串为例,'e'、't'等字符的出现频率通常都是'z'、'j'等字符的数百倍。在这种情况下,就应该从另一角度衡量每个字符的编码长度。

若假设字符 c 出现的概率为 p(c) ≥ 0, 其在二叉编码树中对应的叶子的深度记作depth(c),则:

  • 每个字符 c∈Σ 的带权编码长度为|e(c)| = depth(c) × p(c)
  • 对于任一字符集 Σ 的任一编码方式 e(),Σ 中各字符的平均带权编码长度总和|e(c)|称作 e()(或其对应的二叉编码树)的平均带权编码长度。

例如:信息串" M A M A N I "

各字符出现的概率分别为p('M') = 2/6、p('A') = 2/6、p('I') = 1/6 和p('N') = 1/6

则各字符的带权编码长度分别为:
|e('M')| = 3×(2/6) = 1
|e('A')| = 3×(2/6) = 1
|e('I')| = 2×(1/6) = 1/3
|e('N')| = 1×(1/6) = 1/6

相应地,这一编码方式对应的平均带权编码长度就是:
|e('M')| + |e('A')| + |e('I')| + |e('N')| = 2.5

如何找到最优带权编码树(不唯一)

首先

** 完全二叉编码树 ≠ 平均带权编码最短 **

最优带权编码树有以下性质:

  • 在最优带权编码树中,内部节点的度数均为 2

  • 对于字符出现概率为 p()的任一字符集 Σ ,若字符 x 和 y 在所有字符中的出现概率最低,则必然存在某棵最优带权编码树,使得 x 和 y 在其中同处于最底层,而且互为兄弟。

对于字符出现概率满足一定分布的任一字符集 Σ ,我们都可以按照如下算法来构造其对应的 Huffman 编码树:

首先,对应于 Σ 中的每一字符,分别建立一棵由单个节点组成树,其权重就是该字符出现的频率,这|Σ |棵树组成一个森林 F。

接下来,从 F 中选出权重最小的两棵树,创建一个新节点,并分别以这两棵树作为其左、右子树,从而将它们合成为一棵更高的树,其权重等于其左、右子树权重之和。

这一选取、合并的过程将反复进行,直到最后 F 中只剩下一棵树⎯⎯它就是我们所需要的 Huffman 编码树。

举个例子:

字符 出现频率
A 623
B 99
C 239
D 290
E 906
F 224
基于优先队列的 Huffman 树构造算法

具体方法是:

  • 1,始终将森林中的所有树(根)组织为一个优先队列,比如基于二叉堆实现的优先队列。

  • 2,这样,只要连续地调用 delMin()方法两次,就可以找出当前权重最小的两棵树。

  • 3,在将这两棵树合并为一棵新树之后,可以调用 insert()方法将其重新插入优先队列。

  • 4,这一过程将反复进行,每迭代一次,森林的规模就会减小 1。

因此,经过 n-1 次迭代,森林中将只包含一棵树,即 Huffman 编码树。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,194评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,058评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,780评论 0 346
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,388评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,430评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,764评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,907评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,679评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,122评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,459评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,605评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,270评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,867评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,734评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,961评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,297评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,472评论 2 348

推荐阅读更多精彩内容

  • 树的概述 树是一种非常常用的数据结构,树与前面介绍的线性表,栈,队列等线性结构不同,树是一种非线性结构 1.树的定...
    Jack921阅读 4,442评论 1 31
  • 9.3.3 快速排序   快速排序将原数组划分为两个子数组,第一个子数组中元素小于等于某个边界值,第二个子数组中的...
    RichardJieChen阅读 1,839评论 0 3
  • 1 序 2016年6月25日夜,帝都,天下着大雨,拖着行李箱和同学在校门口照了最后一张合照,搬离寝室打车去了提前租...
    RichardJieChen阅读 5,078评论 0 12
  • 1 数据2 算法3 线性表4 栈5 队列6 串朴素模式匹配算法 -子串的定位操作:从主串中找到子串KMP模式匹配算...
    oldSix_Zhu阅读 1,493评论 0 4
  • 课程介绍 先修课:概率统计,程序设计实习,集合论与图论 后续课:算法分析与设计,编译原理,操作系统,数据库概论,人...
    ShellyWhen阅读 2,265评论 0 3