【数据结构与算法】->数据结构->哈夫曼树->哈夫曼编码&解码

哈夫曼树(Huffman Tree)

    • Ⅰ 前言
    • Ⅱ 什么是哈夫曼树
    • Ⅲ 哈夫曼树的生成及哈夫曼编码
      • A. 构造哈夫曼树
        • a. 频度统计
        • b. 生成哈夫曼树
      • B. 哈夫曼编码
      • C. 解码
    • Ⅳ 总结

Ⅰ 前言

在前面的文章里,我详细讲解了树与二叉树。这篇文章,我们就来看一看二叉树的一种情况——最优二叉树,也称哈夫曼树(Huffman Tree)

对二叉树这个数据结构还不完全清楚的同学可以跳转去下面的文章。

【数据结构与算法】->数据结构->树与二叉树

Ⅱ 什么是哈夫曼树

在前面我们说了,哈夫曼树是二叉树的一种,那到底是什么是哈夫曼树呢?这里我给出一个定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。

完全不知道这个定义在说什么。

不要急,我们慢慢来。

首先来看几个概念。

  • 路径:在一棵树中,一个结点到另一个结点之间的通路,称为路径。比如从根节点到 a ,就是一条路径。
  • 路径长度:在一条路径中,每经过一个结点,路径长度都要加 1 。例如在一棵树中,规定根结点所在层数为1层,那么从根结点到第 i 层结点的路径长度为 i - 1 。比如根节点到 c 和 d 都是 3。
  • 结点的权:给每一个结点赋予一个新的数值,被称为这个结点的权。比如 b 的权是 5。
  • 结点的带权路径长度:指的是从根结点到该结点之间的路径长度与该结点的权的乘积。比如 b 带权路径长度 = 2 * 5 = 10
  • 树的带权路径长度:指树中所有叶子结点的带权路径长度之和。通常记作 “WPL”。比如下图中的树的带权路径长度 WPL = 7 * 1 + 5 * 2 + 2 * 3 + 4 * 3 = 36。

【数据结构与算法】->数据结构->哈夫曼树->哈夫曼编码&解码_第1张图片
所以,当用 n 个结点(都做叶子结点且都有各自的权值)试图构建一棵树时,如果构建的这棵树的带权路径长度最小,称这棵树为“最优二叉树”,也叫“哈夫曼树”。

在构建哈夫曼树时,要使树的带权路径长度最小,只需要遵循一个原则,那就是:权重越大的结点离树根越近。在图 1 中,因为结点 a 的权值最大,所以理应直接作为根结点的孩子结点。

有了这个概念,我们就可以开始构建哈夫曼树了。

Ⅲ 哈夫曼树的生成及哈夫曼编码

在构建哈夫曼树之前,我们先要知道什么是哈夫曼压缩。

压缩算法有很多种,哈夫曼压缩是一种频度压缩。我举一个例子。

假设一个文本文件全部由英文字母构成,那么哈夫曼压缩就是将出现次数(频度)最高的字母用最短的编码来表示。ASCII码占1byte,即8bit,那么将其用2bit的编码来取代,则每个字符会节省6bit的空间。

哈夫曼压缩对应的就是哈夫曼编码,而哈夫曼编码就需要通过哈夫曼树来生成。现在我们来走一遍这个哈夫曼树生成以及哈夫曼编码构建的过程。

A. 构造哈夫曼树

我用一个字符串当作例子来构造一棵哈夫曼树。

egeaefebaeeauefffeeffeebe

a. 频度统计

要构造一棵哈夫曼树,我们需要先知道每个字符的频度。

字符 频度
a 3
b 2
e 12
f 6
g 1
u 1

b. 生成哈夫曼树

我们需要找到最小频度的节点,然后生成新节点,生成过程如下
第一步
【数据结构与算法】->数据结构->哈夫曼树->哈夫曼编码&解码_第2张图片
第二步
【数据结构与算法】->数据结构->哈夫曼树->哈夫曼编码&解码_第3张图片
第三步
【数据结构与算法】->数据结构->哈夫曼树->哈夫曼编码&解码_第4张图片
第四步
【数据结构与算法】->数据结构->哈夫曼树->哈夫曼编码&解码_第5张图片
第五步
【数据结构与算法】->数据结构->哈夫曼树->哈夫曼编码&解码_第6张图片
这样,一棵哈夫曼树就构造完成了。

B. 哈夫曼编码

上一步我们构造出了一棵哈夫曼树,根据这棵树我们现在进行编码。
首先,我们对方向编码,可以向左是0向右是1,也可以反过来,这只是一个编码规则。我定为向左为0.
【数据结构与算法】->数据结构->哈夫曼树->哈夫曼编码&解码_第7张图片
接下来就是从根节点沿着这棵树编码。
比如e,从根节点向左一次就到了,所以e的编码为:0
同样的,比如f,需要从根节点先向右,再向左,所以f的编码是:10

按照以上规律,我们可以写出哈夫曼编码

字符 编码
a 110
b 1110
e 0
f 10
g 11110
u 11111

所以egeaefebaeeauefffeeffeebe转化成哈夫曼编码为:
011110011001001110110001101111101010100010100011100

哈夫曼编码完成。

C. 解码

解码依旧是根据构造的哈夫曼树,以及你制定的编码规则。

011110011001001110110001101111101010100010100011100

根据这个编码,我做几个解码。
从根节点,先向左,到了e,所以第一个是e,然后回到根节点。
向右,向右,向右,向右,向左,到了g,所以第二个是g,再回到根节点。

根据这个规律,按照之前构造的哈夫曼树还原出这串字符串。
这就是解码的实现。

Ⅳ 总结

哈夫曼编码其实在生活中非常常用到,因为它的压缩率比较高,而且丢包率也很低。

这篇文章只是作为一个引子,简单讲述了哈夫曼编码的生成原理以及思想,下面的两篇文章就是实战了,我们将用哈夫曼编码的思想,实现一个真正可以压缩解压缩文件的程序,大家若有兴趣可以来看一看,自己动手和我一起实现一个有意思的程序。

【C语言->数据结构与算法】->哈夫曼压缩&解压缩->第一阶段->哈夫曼编码&解码的实现

【C语言->数据结构与算法】->哈夫曼压缩&解压缩->终局->压缩率百分之八十六

你可能感兴趣的:(数据结构与算法,二叉树,数据结构,算法,c语言,哈夫曼树)