【树专题】哈夫曼树和哈夫曼编码详解

一. 哈夫曼树相关概念

一般默认哈夫曼树????为二叉树

哈夫曼树(赫夫曼树 - Huffman树)又叫最优二叉树

特点:带权路径最短

树的带权路径长度(WPL Weighted path length):指树中的所有叶子结点*对应的路径长度的总和

【树专题】哈夫曼树和哈夫曼编码详解

例如上图,叶子结点a、b、c、d的权值分别为7、5、2、4,那么这棵二叉树的带权路径长度
WPL=7×2+5×2+2×3+4×2=38WPL = 7 \times 2 + 5 \times 2 + 2 \times 3 + 4 \times 2 = 38

二. 哈夫曼树的构造方法

给定n个权值,用这n个权值来构造哈夫曼树????的算法描述如下:
1)将这n个权值分别看作只有根节点的n棵二叉树,这些二叉树构成集合F
2)从F中选根节点权值最小的树(假设为a、b)作为左、右子树,构造一颗新的二叉树(c),新的二叉树的根节点的权值为左、右子树根节点权值之和
3)从F中删去a、b,加入新构造的树c
4)重复2)3)两步,直到F中只剩下一棵树为止,这棵树就是哈夫曼树

说明:一般构造哈夫曼树的潜规则是左子树根的权值<=右子树根的权值

示例
【树专题】哈夫曼树和哈夫曼编码详解

三. 哈夫曼树的特点

1)权值越大的点,距离根节点越近
2)树的带权路径长度最短
3)树中没有度为1的点

四. 哈夫曼编码

我们能否利用哈夫曼树的特点来做一些事情呢?比如在存储文件时,对于包含同一内容的文件有多种存储方式,是不是可以找到一种最节省空间的存储方法?答案是可以的,利用哈夫曼编码编码就可以达到目的

常见的.zip压缩文件和.jpeg图片文件的底层技术都用到了哈夫曼编码

具体示例
我们现在一串字符串“S = AAABBAC”

如果我们选择用00来表示A,01来表示B,10来表示C(这里用的是二进制)
那么S可以编码为T(S)=00000001010010T(S) = 00000001010010 ,长度为14

而如果我们以每个字符出现的次数为权值去构造一棵二叉树,并且对构造的二叉树的每个结点的左右分支进行编号,如下图所示

【树专题】哈夫曼树和哈夫曼编码详解

表:字符在字符串中的出现次数统计

A B C
4次 2次 1次

表:对A、B、C的哈夫曼编码规则

A B C
1 01 00

此时S可以编码为H(S)=1110101100H(S) = 1110101100 ,长度为10

????上述从哈夫曼树导出每个字符的编码,进而得到对整个字符串的编码的过程称为哈夫曼编码

显然H(s)比T(s)小

说明

  • T(s)采用的是定长码,而H(s)采用的是不定长码(哈夫曼编码)

  • 解码过程:对H(s)解码是根据哈夫曼树,一次一次沿着根节点走向叶子结点并读出字符的过程

  • 在解码的时候哈夫曼编码是不会产生歧义的
    原因是:哈夫曼编码规则产生的都是前缀码,即任意字符的编码串都不是另一个字符串的前缀,根通往任一叶子结点的路径都不可能是通往其余叶子结点路径的子路径,因此不会有歧义

  • 对于同一组结点,构造出的哈夫曼树可能不唯一,如a、b、c、d权值分别为3、2、2、2

  • 除了常见的哈夫曼二叉树,还有哈夫曼n叉树

五. 哈夫曼树的应用

哈夫曼问题C++代码描述

Acwing148.合并果子(哈夫曼问题+小根堆)

判断是否为满k叉树

哈夫曼 kk 叉树可能有多余结点,计算公式 多余结点t = (N-1) % (k - 1)
如果t=0t = 0说明是满k叉树

【树专题】哈夫曼树和哈夫曼编码详解

如果不是满k叉树,我们有两种方法让它变成满的
1)把(多余的+1)个合并成1个
2)缺少的结点用0来补充,然后把0也看作权值

给定有序数组,如何以O(N)复杂度构造哈夫曼树

K叉哈夫曼树构造方法 O(N)
这篇博客思路是对的,代码我还没试过

其他应用
阿里笔试题—字符串"alibaba"的二进制哈夫曼编码有多少位


写在最后:我的博客主要是对计算机领域所学知识的总结、回顾和思考,把每篇博客写得通俗易懂是我的目标,分享技术和知识是一种快乐 ,非常欢迎大家和我一起交流学习,有任何问题都可以在评论区留言,也期待与您的深入交流(^∀^●)