一文搞懂哈夫曼树
哈夫曼树介绍
hello,大家好,我是bigsai。
哈夫曼树、哈夫曼编码很多人可能听过,但是可能并没有认真学习了解,今天这篇就比较详细的讲一下哈夫曼树。
首先哈夫曼树是什么?
哈夫曼树的定义:给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree),哈夫曼树是带权路径长度最短的树。权值较大的结点离根较近。
那这个树长啥样子呢?例如开始2,3,6,8,9权值节点构成的哈夫曼树是这样的:
从定义和图上你也可以发现下面的规律:
- 初始节点都在树的叶子节点上
- 权值大的节点离根更近
- 每个非叶子节点都有两个孩子(因为我们自下向上构造,两个孩子构成一个新树的根节点)
你可能会好奇这么一个哈夫曼树是怎么构造的,其实它是按照一个贪心思想和规则构造,而构造出来的这个树的权值最小。这个规则下面会具体讲解。
哈夫曼树非常重要的一点:WPL
(树的所有叶结点的带权路径长度之和)。至于为什么按照哈夫曼树方法构造得到的权重最小,这里不进行证明,但是你从局部来看(三个节点)也要权值大的在上一层WPL才更低。
WPL计算方法: WPL=求和(Wi * Li)其中Wi是第i个节点的权值(value)。Li是第i个节点的长(深)度.
例如上面 2,3,6,8,9权值节点构成的哈夫曼树的WPL计算为(设根为第0层):
比如上述哈夫曼树的WPL
为:2*3+3*3+6*2+8*2+9*2=(2+3)*3+(6+8+9)*2=61
.
既然了解了哈夫曼树的一些概念和WPL的计算方式,下面看看哈夫曼树的具体构造方式吧!
哈夫曼树构造
初始给一个森林有n个节点。我们主要使用贪心的思想来完成哈夫曼树的构造:
- 在n个节点找到两个最小权值节点(根),两个为叶子结构构建一棵新树(根节点权值为左右孩子权值和)
- 先删掉两个最小节点(n-2)个,然后加入构建的新节点(n-1)个
- 重复上面操作,一直到所有节点都被处理
在具体实现上,找到最小两个节点需要排序操作,我们来看看2,6,8,9,3权值节点构成哈夫曼树的过程。
初始时候各个节点独立,先将其排序(这里使用优先队列),然后选两个最小节点(抛出)生成一个新的节点,再将其加入优先队列中,此次操作完成后优先队列中有5,6,8,9节点
重复上面操作,这次结束 队列中有11,8,9节点(排序后8,9,11)
如果队列为空,那么返回节点,并且这个节点为整个哈夫曼树根节点root。
否则继续加入队列进行排序。重复上述操作,直到队列为空。
在计算带权路径长度WPL的时候,需要重新计算高度(从下往上),因为哈夫曼树是从下往上构造的,并没有以常量维护高度,可以构造好然后计算高度。
具体代码实现
import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.PriorityQueue; import java.util.Queue; public class HuffmanTree { public static class node { int value; node left; node right; int deep;//记录深度 public node(int value) { this.value=value; this.deep=0; } public node(node n1, node n2, int value) { this.left=n1; this.right=n2; this.value=value; } } private node root;//最后生成的根节点 List<node>nodes; public HuffmanTre
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
让数据结构与算法学习更简单,每一种数据结构与算法通过多图的方式讲解、实现、解题,内容覆盖递归详解、单双链表、堆、栈、二叉树(遍历、插删)、AVL树、哈夫曼树、字典树、dfs、bfs、拓扑排序、Dijkstra、Floyd、并查集、跳表、分治算法、动态规划、快速幂、十大排序等等。 还覆盖超经典面试笔试题例如:topK问题、约瑟夫环问题、链表找环问题、LRU、20+道经典动态规划问题!