赫夫曼树原理以及java实现
##1.最优二叉树(赫夫曼树)
###在学习赫夫曼树之前,我们了解一下路径与路径长度的概念
###1.1:路径:从树的一个结点到另一个结点之间的分支构成这两个节点之间的路径
###1.2:路径长度:路径上的分支数目称作路径长度
###1.3:树的路径长度:是从树根到每一结点的路径长度之和
###1.4:结点的权:赋予结点上的一个有意义的实数
###1.5:结点的带权路径长度:从该结点到树根之间的路径长度与该结点上权的乘积
###1.6:树的带权路径长度:为树中所有叶子结点的带权路径长度之和==>WPL
###假设有n个权值{w1,w2,…wn},试构造一颗有n个叶子结点的二叉树,每个叶子结点带权为wi,则其中带权路径长度WPL最小的二叉树称作最优二叉树或赫夫曼树
###例如:
###图中的三颗二叉树,都有4个叶子结点a,b,c,d分别带权7,5,2,4,它们的带全路径长度分别为
###(a)WPL=7x2+5x2+2x2+4x2=36
###(b)WPL=7x3+5x3+2x1+4x2=46
###(c)WPL=7x1+5x2+2x3+4x3=35
###其中以(c)树的为最小,则它为赫夫曼树
##2.构造赫夫曼树
###(1)根据给定的n个权值{w1,w2,…wn}构成n颗二叉树集合F={T1,T2,…Tn}其中每棵二叉树Ti中只有一个带权为wi的根结点,其左右子树均为空
###(2)在F中选取两颗根结点权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为其左右子树上根结点的权值之和
###(3)在F中删除这两棵树,同时将新得到的二叉树加入F中
###(4)重复(2)和(3),直到F只含一棵树为止。这棵树便是赫夫曼树。
##3.java实现构造赫夫曼树代码
结点元素
package HuffmanTree;
public class TreeNode {
public char data; //字符
public int weight; //权值
public TreeNode left;
public TreeNode right;
public TreeNode(char data,int weight) {
this.data=data;
this.weight=weight;
}
public void setLeft(TreeNode left) {
this.left = left;
}
public void setRight(TreeNode right) {
this.right = right;
}
public TreeNode getLeft() {
return left;
}
public TreeNode getRight() {
return right;
}
public int getWeight() {
return weight;
}
}
构建赫夫曼树/层次遍历
package HuffmanTree;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
public class createHeffumanTree {
/**
* 构建赫夫曼树 返回其树根节点
* @param nodes 结点
* @return
*/
public static TreeNode creatTree(List<TreeNode> nodes) {
//当集合中只有一棵树时,赫夫曼树构建完成
while(nodes.size()>1) {
//对所有结点进行升序(根据权值)
qiukSort(nodes, 0, nodes.size()-1);
//创建新的结点,新结点的权值等于前最小的两个权值之和
TreeNode newNode=new TreeNode('X', nodes.get(0).getWeight()+nodes.get(1).getWeight());
//将最小的两个结点作为新结点的左右子树
newNode.setLeft(nodes.get(0));
newNode.setRight(nodes.get(1));
//清除最小权值的两个结点
nodes.remove(0);
nodes.remove(0);
//将新构建的结点加入集合中
nodes.add(newNode);
}
//返回根节点
return nodes.get(0);
}
/**
* 快速排序----对根据结点的权值 进行升序排列
* @param nodes
* @param left
* @param right
*/
public static void qiukSort(List<TreeNode> nodes, int left,int right){
if(left<right) {
int i=left;
int j=right+1;
TreeNode index=nodes.get(left);
while(true) {
while(i<right&&nodes.get(++i).weight<=index.weight);
while(left<j&&nodes.get(--j).weight>=index.weight);
if(i<j) {
//交换
TreeNode node=nodes.get(i);
nodes.set(i, nodes.get(j));
nodes.set(j, node);
}else {
break;
}
}
//交换
TreeNode node=nodes.get(left);
nodes.set(left, nodes.get(j));
nodes.set(j, node);
//递归
qiukSort(nodes, left, j-1);
qiukSort(nodes, j+1, right);
}
}
/**
* 层次遍历(广度优先搜索)
* @param root
*/
public static void printTree(TreeNode root) {
Queue<TreeNode> queue=new ArrayDeque<TreeNode>();
//根节点入列
queue.offer(root);
while(!queue.isEmpty()) {
//移除已打印元素(头部)
TreeNode head=queue.remove();
//这里我们打印-----权值
System.out.print(head.getWeight()+" ");
if(head.getLeft()!=null) {
queue.offer(head.getLeft());
}
if(head.getRight()!=null) {
queue.offer(head.getRight());
}
}
}
public static void main(String[] args) {
List<TreeNode> nodes=new ArrayList<TreeNode>();
nodes.add(new TreeNode('A', 20));
nodes.add(new TreeNode('B', 40));
nodes.add(new TreeNode('C', 10));
nodes.add(new TreeNode('D', 5));
nodes.add(new TreeNode('E', 15));
nodes.add(new TreeNode('F', 15));
//获取赫夫曼树的根节点
TreeNode root= creatTree(nodes);
//打印赫夫曼树(层次遍历)
printTree(root);
}
}
打印结果如下
105 40 65 30 35 15 15 15 20 5 10
构建的赫夫曼树如图
感谢支持!!!!!!