
哈夫曼树简介
哈夫曼树,英文名huffman tree,它是一种的叶子结点带有权重的特殊二叉树,也叫最优二叉树。
哈夫曼(Huffman)编码是上个世纪五十年代由哈夫曼教授研制开发的,它借助了数据结构当中的树型结构,在哈夫曼算法的支持下构造出一棵最优二叉树,我们把这类树命名为哈夫曼树。
哈夫曼树核心
1)路径
在一棵树中,一个节点到另一个节点之间的通路,称为路径,如下图中的根节点到a之间的通路:

2)路径长度
在一条路径中,每经过一个节点,路径长度就加1,如上图根节点到节点c的路径长度为3:

3)节点的权
每个节点赋予一个新的数值,如a的权为7,b的权为5,如下图所示:

4)节点的带权路径长度
从根结点到该结点之间的路径长度与该结点的权的乘积,如下图所示:

如b的带权路径长度为2*5=10。
5)树的带权路径长度
树中所有叶子结点的带权路径长度之和,通常记作 “WPL” ,如下图中所示:

这颗树的带权路径长度为:WPL = 7 * 1 + 5 * 2 + 2 * 3 + 4 * 3
赫夫曼树中有一个很重要的概念就是带权路径,带权路径最小的才是赫夫曼树,权值较大的结点离根较近。
哈夫曼树的特征

从定义和图上你也可以发现下面的规律:
- 初始节点都在树的叶子节点上;
- 权值大的节点离根更近;
- 每个非叶子节点都有两个孩子:因为我们自下向上构造,两个孩子构成一个新树的根节点。
哈夫曼树的构造
你可能会好奇一个哈夫曼树是怎么构造的,其实它是按照一个贪心思想和规则构造,而构造出来的这个树的权值最小。
基本步骤,大致分为如下3步:
1)从小到大进行排序, 将每一个数据,每个数据都是一个节点 , 每个节点可以看成是一颗最简单的二叉树;
2)取出根节点权值最小的两颗二叉树,组成一颗新的二叉树, 该新的二叉树的根节点的权值是前面两颗二叉树根节点权值的和;
3)再将这颗新的二叉树,以根节点的权值大小再次排序, 不断重复 1-2-3 的步骤,直到数列中,所有的数据都被处理,就得到一颗赫夫曼树。
下面我用图形的方式来还原构造过程。
1)初始构建森林
我们把每一个叶子结点,都当做树一颗独立的树,只有根结点的树,这样就形成了一个森林,如下图所示:

2)每次取两个最小权值顶点,构造父节点。
再将这颗新的二叉树,以根节点的权值大小 再次排序,如下图所示:

3)否不断重复上面的步骤,直到数列中,所有的数据都被处理,就得到一颗赫夫曼树。
如下图所示:

最后,这棵哈夫曼树的WPL就为:
2*3+3*3+6*2+8*2+9*2=(2+3)*3+(6+8+9)*2=61
哈夫曼树代码实现
package 二叉树;
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 HuffmanTree() {
this.nodes=null;
}
public HuffmanTree(List<node>nodes)
{
this.nodes=nodes;
}
public void createTree() {
Queue<node>q1=new PriorityQueue<node>(new Comparator<node>() {
public int compare(node o1, node o2) {
return o1.value-o2.value;
}});
q1.addAll(nodes);
while(!q1.isEmpty())
{
node n1=q1.poll();
node n2=q1.poll();
node parent=new node(n1,n2,n1.value+n2.value);
if(q1.isEmpty())
{
root=parent;return;
}
q1.add(parent);
}
}
public int getweight() {
Queue<node>q1=new ArrayDeque<node>();
q1.add(root);
int weight=0;
while (!q1.isEmpty()) {
node va=q1.poll();
if(va.left!=null)
{
va.left.deep=va.deep+1;va.right.deep=va.deep+1;
q1.add(va.left);q1.add(va.right);
}
else {
weight+=va.deep*va.value;
}
}
return weight;
}
public static void main(String[] args) {
List<node>list=new ArrayList<node>();
list.add(new node(2));
list.add(new node(3));
list.add(new node(6));
list.add(new node(8));list.add(new node(9));
HuffmanTree tree=new HuffmanTree();
tree.nodes=list;
tree.createTree();
System.out.println(tree.getweight());
}
}
关于mikechen
mikechen睿哥,10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。