1. 基本概念
哈夫曼树:给定n个权值作为n个叶子节点,构造一棵二叉树,若该数的带权路径长度达到最小,这样的二叉树称为最优二叉树,也叫做哈夫曼树(Huffman Tree)。哈夫曼树是一个带权路径长度最短的树,其中权值越大的节点离根节点越近。
路径:在一棵树中,从一个节点往下可以到达的孩子或孙子节点之间的通路,称为路径。
路径长度:通路中分支的数组称为路径长度。若规定根节点的层数为1,则从根节点到第N层节点的路径长度为N-1.
节点的权:若将数中节点赋给一个某种含义的数值,则这个数值成为节点的权。
节点的带权路径长度:从根节点到该节点之间的路径长度与该节点权的乘积。
即:带权路径长度 = 路径长度 * 该节点权
树的带权路径长度:所有叶子节点的带权路径长度之和。记为WPL。
哈夫曼树:带权路径长度最小的就是哈夫曼树。即WPL最小。
示例:
wpl: 13 * 1 + 8 * 2 + 7 * 3 + 3 * 3 = 59
2. 步骤
把一个数组构建称哈夫曼树的步骤:
- 把数组从小到大进行排序,每个数据都是一个节点,每个节点都可以看成一个最简单的二叉树。
- 取出根节点权最小的两棵二叉树。
- 组成一棵新的二叉树,该树的根节点为去出的两棵二叉树的权值和。
- 将这棵新的二叉树,以根节点的权值进行大小排序。然后把这个新的二叉树的根节点放入数组中。重复1234的步骤,直到数组中只剩下一个树的时候,所有的数据都被处理。这时就得到了一棵哈夫曼树。
3. 示例代码
package HafmTree;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class HafumanTree {
public static void main(String[] args) {
int[] arr = {
13, 7, 8, 3, 29, 6, 1};
NodeTree root = createHafmanTree( arr );
//测试
preOrder( root );
}
//编写一个前序遍历的方法
public static void preOrder(NodeTree root) {
if(root != null){
root.preOreder();
}else {
System.out.println("是空树,不能遍历");
}
}
public static NodeTree createHafmanTree (int[] arr){
//1. 把数组中的每一个值都创建成一个NodeTree节点
List<NodeTree> nodes = new ArrayList<NodeTree>( );
for(int value : arr){
nodes.add(new NodeTree( value ));
}
while(nodes.size() > 1){
//2. 从小到大进行排序
Collections.sort( nodes );
//3. 取出根节点权值最小的两棵二叉树
NodeTree leftNode = nodes.get( 0 );
NodeTree rightNode = nodes.get( 1 );
//4. 构建一棵新的二叉树
NodeTree parent = new NodeTree( leftNode.value + rightNode.value );
parent.left = leftNode;
parent.right = rightNode;
//5. 从nodes中删除处理过的节点
nodes.remove( 1 );
nodes.remove( 0 );
nodes.add( parent );
}
//返回哈夫曼树的root节点
return nodes.get( 0 );
}
}
//定义树的结构
class NodeTree implements Comparable<NodeTree> {
int value; //权值
NodeTree left; //指向左节点
NodeTree right; //指向右节点
public NodeTree (int value){
this.value = value;
}
//前序遍历二叉树
public void preOreder() {
System.out.println(this);
if(this.left != null){
this.left.preOreder();
}
if(this.right != null){
this.right.preOreder();
}
}
public String toString() {
return "TreeNode [value=" + value + "]";
}
@Override
public int compareTo(NodeTree o) {
return this.value - o.value;
}
}
总结:
本文使用java完成了一个最简单的哈夫曼树。哈夫曼树还有很多实际的应用,比如编码表的压缩等