一、哈夫曼树概述
1.1 什么是哈夫曼树
给定 n 个权值作为 n 个叶子节点,构造一棵二叉树,若该树的带权路径长度(Weighted Path Length of Tree)达到最小, 称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。
哈夫曼树是带权路径长度最短的树,权值较大的节点离根较近。
1.2 哈夫曼树重要概念
路径和路径长度:
在一棵树中,从一个节点往下可以到达孩子或孙子节点的通路,称为路径。
通路中分支的数目称为路径长度。若规定根节点的层数为 1,则从根节点到第 L 层节点的路径长度为 L-1。
节点的权及带权路径长度:
若给树中节点赋予一个有着某种含义的数值,则这个数值称为该节点的权。
节点的带权路径长度为:从根节点到该节点之间的路径长度与该节点的权的乘积。
树的带权路径长度:
树的带权路径长度规定为所有叶子节点的带权路径长度之和,记为 WPL(Weighted Path Length of Tree)。权值越大的节点离根节点越近的二叉树才是最优二叉树。
直接看概念,可能有一点抽象。如下图所示,是同一序列构成的不同二叉树的三种情况:
其中 WPL 最小的就是最优二叉树,即第二个是最优二叉树。
二、哈夫曼树的创建思路
给定一个序列,创建哈夫曼树的基本思路如下:
- 将序列从小到大进行排序;
- 将每一个数据看作是一个节点,每个节点可以看成是一颗最简单的二叉树;
- 取出根节点权值最小的两颗二叉树组成(权值较小的作为左节点,较大的作为右节点)一颗新的二叉树,该新的二叉树的根节点的权值是前面两颗二叉树根节点权值的和;
- 在原序列中将步骤 3 取出的两个根节点移除,然后将它们组成的新的二叉树的根节点放入到原序列中;
- 不断重复 1-2-3-4 的步骤,直到序列中只剩下一个节点,该节点就是哈夫曼树的根节点。
【图解分析】
下面将以序列 {13, 7, 8, 3} 为例,图解创建哈夫曼树的过程。
-
首先,序列升序排序得到 {3, 7, 8, 13}。
-
把每个数据看做是一个节点,取出节点权值最小的两个节点 3, 7 组成一颗新的二叉树,该二叉树权值为 3+7 = 10。
-
在原序列中将第 2 步取出的两个权值最小的移除,然后将第 2 步生成的新节点的权值加入到原序列中,并重新排序。
-
再次取出权值最小的两个节点 8, 10 组成一颗新的二叉树,新的二叉树权值为 8+10 = 18。然后从序列中移除节点 8,10,将 18 添加进去,然后重新排序。
-
再次取出权值最小的两个节点 13,18 组成一颗新的二叉树,新的二叉树权值为 13+18 = 31。然后从序列中移除 13, 18,将 31 添加进去。此时序列中只剩下一个节点,该节点即为哈夫曼树的根节点。
至此,序列 {13, 7, 8, 3} 的哈夫曼树创建完毕。
三、哈夫曼树的代码实现
哈夫曼树的完整代码实现如下:
/**
* @Des