什么是哈夫曼树?
给定n个值作为n个叶子节点,构造出一个二叉树,若该数的wpl(该树的带权路径长度)最小,那么这样的二叉树被称为最优二叉树,同时也被称为哈夫曼树。
那么怎么计算wpl?
wpl=5❌2+7❌2+2❌2+13❌2= 54
结点的权及带权路径长度:若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。
结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
树的带权路径长度:树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为 WPL(weighted path length) ,权值越大的结点离根结点越近的二叉树才是最优二叉树。
创建哈夫曼树步骤:
题:给定1个数组,构建1个哈夫曼树
1.从小到大进行排序,将每一个数都当做一个节点,每个节点都是1个二叉树。
2.取出根节点权值最小的两棵二叉树。
3.再创建1个新的二叉树,该二叉树的根节点的权值是前面两棵二叉树的权值之和。
4.将新的二叉树代入进行重新排序,重复前4个步骤,直到数列中的所有数全被处理。
代码实现:
代码中的前序遍历代码:
链接: 前序遍历和数的创建
注意:
该代码排序用的是Collections中的sort方法,用该方法需要实现Comparable接口,并重写里面的CompareTo方法。
public class HeFuManTree {
public static void main(String[] args) {
int arr[] = {13,7,8,3,29,6,1};
Node haFuManTree = createHaFuManTree(arr);
preOrder(haFuManTree);
}
public static Node createHaFuManTree(int[] arr){
//1.先遍历数组
//2.将arr中的每个元素构成1个Node
//3.将Node放入ArryList中
List<Node> nodes = new ArrayList<Node>();
for (int value : arr) {
nodes.add(new Node(value));
}
//只要nodes中元素大于1个就不断进行该操作
while (nodes.size() > 1){
//先排序(从小到大),注:要想用Collections工具类中Sort方法进行排序就必须实现Comparable方法
Collections.sort(nodes);
//取出权值最小的1个数,当从小到大排完后,最小的就是第一个数
//用它来充当左子节点
Node leftNode = nodes.get(0);
//取出权值第二小的数,当从小到大排完后,最小的就是第二个数
//用它来充当右子节点
Node rightNode = nodes.get(1);
//构建1个新的二叉树
//新的二叉树的根节点(root)就是前两个左右子节点的值和
Node parentNode = new Node(leftNode.value + rightNode.value);
//将新的二叉树的左右子节点也进行赋值操作
parentNode.left = leftNode;
parentNode.right = rightNode;
//从ArrayList中删除原本的二叉树
nodes.remove(leftNode);
nodes.remove(rightNode);
//将新的二叉树加入nodes中
nodes.add(parentNode);
}
return nodes.get(0);
}
//传入头节点(root)
public static void preOrder(Node root){
if(root != null){
root.preOrder();
}else {
System.out.println("为null");
}
}
}
class Node implements Comparable<Node>{
int value; //该节点的值
Node left; //该节点的左子节点
Node right; // 该节点的右子节点
//创建1个构造器
public Node(int value){
this.value = value;
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
@Override
public int compareTo(Node o) {
//表示从小到大进行排序
return this.value - o.value;
}
//编写1个前序遍历的方法
public void preOrder(){
//先输出头节点(root)
System.out.println(this);
//如果左子树不为null,就递归左子树
if(this.left != null){
this.left.preOrder();
}
if(this.right != null){
this.right.preOrder();
}
}
}