赫夫曼树的实现及编码
一、赫夫曼树简介
1、简介
1)给定n个权值(节点的值)作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称这样的二叉树为 赫夫曼树(哈夫曼树、霍夫曼树,最优二叉树)。
2)赫夫曼树是带权路径长度最短的树,权值较大的结点离根较近
2、相关定义
1、路径:从一个节点往下可以到达子节点的之间的通路;
2、路径长度:通路中分支的数目。若规定跟节点所在的层数为1,则从根节点到第L层节点的路径长度为L-1;
3、节点的权:给树中的节点赋予一个有着某种含义的值;
4、节点的带权路径:从根结点到该结点之间的路径长度与该结点的权的乘积
5、WPL(weighted path length)树的带权路径长度:规定为所有叶子节点的带权路径长度之和。 权值越大的结点离根结点越近的二叉树才是最优二叉树。
WPL最小的树就是赫夫曼树:
二、赫夫曼树算法
1、算法思路
将数列 arr={12,3,5,8,34},转成一颗赫夫曼树,步骤如下:
1、从小到大对数组进行排序,将每个数值存入 ArrayList 链表,每个数值都是一个节点,每个节点可以看成一个最简单的二叉树。
2、从 ArrayList 取出根节点权值最小的两颗二叉树,组成一颗新的二叉树,该新的二叉树的根节点的权值就是前两颗二叉树根节点权值的和。
3、然后从 ArrayList 中将前两颗二叉树根节点remove,再把新的二叉树的根节点的权值放入 ArrayList 中,然后再次排序。
4、不断重复上述步骤,直到 ArrayList 中只剩下 赫夫曼树的根节点时退出循环,这样就可以得到一棵赫夫曼树了。
2、代码实现
import java.util.ArrayList;
import java.util.Collections;
/**
* 哈夫曼树:最优二叉树
*/
public class HuffManTree {
public static void main(String[] args) {
int[] arr = {
12,3,5,8,34};
//生成赫夫曼树
Node huffManTree = createHuffManTree(arr);
//前序遍历赫夫曼树
preOrder(huffManTree);
}
//创建赫夫曼树的方法
public static Node createHuffManTree(int[] arr) {
//遍历arr数组,将arr的每个元素构建成一个NOde,将Node放入ArrayList;
ArrayList<Node> nodes = new ArrayList<>();
for (int value : arr) {
nodes.add(new Node(value));
}
//循环,直到ArrayList只剩一个节点时结束
while (nodes.size() > 1) {
//从大到小排序
Collections.sort(nodes);
//取出权值最小的两个节点(二叉树)
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);
//将父节点加入到ArrayList
nodes.add(parent);
}
//最后返回赫夫曼树的头就可以了
return nodes.get(0);
}
//编写一个前序遍历的方法
public static void preOrder(Node root){
if(root!=null){
root.preOrder();
}else {
System.out.println("空树,无法遍历");
}
}
}
/**
* 创建节点类
* 为了让NOde对象支持排序COllectins 集合排序
* 让Node 实现Comparable 接口
*/
class Node implements Comparable<Node> {
int value;//节点权值
Node left;//左子节点
Node right;//右子节点
//前序遍历
public void preOrder(){
System.out.println(this);
if(this.left!=null){
this.left.preOrder();
}
if(this.right!=null){
this.right.preOrder();
<