数据结构之二叉树(五):哈夫曼树
基本介绍:
给定n个权值作为n个叶子节点,若该树的带权路径长度(WPL)达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树。
哈夫曼树是带权路径长度最短的树,权值最大的节点离根较近。
基本术语:
路径和路径长度
在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
结点的权及带权路径长度
若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
树的带权路径长度
树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。
举例说明:
该树的带权路径长度(WPL)=13x2+7x2+8x2+3x2=62
该树的带权路径长度为7x1+3x2+8x3+13x3=76
构建一棵哈夫曼树的步骤
1)从小到大进行排序,每一个数据都是一个节点,都可以看成一颗最简易的二叉树。
2)取出根节点权值最小的两棵二叉树组成一棵新的二叉树,该新的二叉树的根节点的权值是前面两棵二叉树根节点权值的和
3)再将这棵新的二叉树,以根节点的权值大小再次进行排序,不断重复这三步,直到所有数据全部被处理,便构建成了一棵哈夫曼树。
以下为举例说明:
权值为13,7,8,3,29,6,1的节点构建一棵二叉树。
首先对其进行升序排序:1,3,6,7,8,13,29
第一步:首先取出根节点权值最小的两棵树构建成一棵新的二叉树,即取1,3出来。变成如下:
**第二步:**新得的树的根节点的权值便成了4,接着让其加入剩下的节点再次排序,便是4,6,7,8,13,29,再次进行第一步(取4,6)得到图下:
第三步:将新得到的根节点权值为10的新树与剩下的树再次进行排序,得到7,8,10,13,29,再次进行第一步,得到图下:
**第四步:**得到的根节点权值为15的新树再次排序,得10,13,15,29,再次进行第一步得图下:
第五步:如此循环往复,直到所有节点皆被使用完,最终得到如下图:
**
java代码创建哈夫曼树
**:
package Tree05;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class HuffmanTree {
public static void main(String[] args) {
int arr[]= {13,7,8,3,29,6,1};
Node root = createHuffmanTree(arr);
frontShow(root);
}
//创建哈夫曼树
public static Node createHuffmanTree(int[] arr) {
//遍历arr数组,将arr的每个元素构建成一棵树(Node)
//再将Node放入到ArrayList中
List<Node> nodes=new ArrayList<Node>();
for(int value: arr) {
nodes.add(new Node(value));
}
while(nodes.size()>1) {
//排序,升序
Collections.sort(nodes);//node实现了Comparable接口,可以直接进行排序
//取出权值最小的两棵二叉树
Node leftNode=nodes.get(0);
Node rightNode=nodes.get(1);
//构建一棵新的二叉树
Node parent=new Node(leftNode.value+rightNode.value);
parent.left=leftNode;
parent.right=rightNode;
//从ArrayList中删除处理过的二叉树
nodes.remove(leftNode);
nodes.remove(rightNode);
//将parent加入到nodes
nodes.add(parent);
}
//返回哈夫曼树的root节点
return nodes.get(0);
}
//前序遍历
public static void frontShow(Node root) {
if(root!=null) {
root.frontShow();
}else {
System.out.println("空树,不能遍历");
}
}
}
//创建节点类
//便于节点按权值进行排序,实现Comparable接口
class Node implements Comparable<Node>{
int value;//节点权值
Node left;//左子节点
Node right;//右子节点
public Node(int value) {
this.value=value;
}
@Override
public String toString() {
return "Node [value=" + value + "]";
}
@Override
public int compareTo(Node o) {
// TODO Auto-generated method stub
//表示从小到大进行排序
return this.value - o.value;
}
public void frontShow() {
System.out.println(this);
if(this.left!=null) {
this.left.frontShow();
}
if(this.right!=null) {
this.right.frontShow();
}
}
}
输出结果: