霍夫曼树
定义:给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为赫夫曼树(Huffman Tree)。什么赫夫曼树,霍夫曼树都是翻译的不同产物罢了;
路径:从一个节点到另一个节点的通路称为路径;
路径的长度:路径中通过节点两两连线的个数即为路径长度;
权:节点中的值即为权;
带权路径长度:路径长度*权=带权路径长度
树的带权路径长度:所有叶子节点的带权路径长度之和,记为WPL(由此可见权值大的,离根节点越近的越优)
赫夫曼树:WPL最小的树
下面的方法为:将该数组 arr={14,9,10,5,29,7,2} 化为Huffman树
代码:
>思路:
给定一个数组,将其写成赫夫曼树
>步骤:
1. 创建一个结合,用于存放入节点
2. 将数组的每一项创建成一个节点(每一项的值为该节点的权)
3. 对每个节点的权进行比较(实现Comparable接口的方法,调用工具类Collections的sort方法)
4. 得到权值有序的集合
5. 得到集合的第0项和第一项的权值之和,并创建该权值的节点,称之为父节点,并将父节点add到集合中
6. 将第0项和第一项分别设置为父节点的左右子节点,并remove这两个子节点
7. 将新的集合排序(Collections的sort方法)
8. 然后继续上面的操作,直到只剩下一个节点
9. 此时以该节点为根节点对应的树,即为Huffman树
10. 此时对该节点进行前序遍历
节点类:
public 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) {
//this.value-o.value:添加的node按照从小到大的顺序
return this.value-o.value;
}
}
操作类:
public class HuffmanTree {
public static void main(String[] args) {
int[] arr={14,9,10,5,29,7,2};
Node huffman = huffman(arr);//得到赫夫曼树的根节点
perOrder(huffman);//打印出赫夫曼树的前序遍历
}
//得到赫夫曼树,该方法返回赫夫曼树的根节点
public static Node huffman(int[] arr){
ArrayList<Node> nodes = new ArrayList<>();
for (int value : arr) {
nodes.add(new Node(value));
}
while (nodes.size()>1) {
Collections.sort(nodes);//将nodes排序
Node leftNode = nodes.get(0);
Node rightNode = nodes.get(1);
Node parent = new Node(leftNode.value + rightNode.value);
nodes.add(parent);
parent.left = leftNode;
parent.right = rightNode;
nodes.remove(leftNode);
nodes.remove(rightNode);
}
return nodes.get(0);
}
//前序遍历,传入赫夫曼的根节点,返回赫夫曼树的前序遍历
public static void perOrder(Node node){
System.out.println(node);
if (node.left!=null){
perOrder(node.left);
}
if (node.right!=null){
perOrder(node.right);
}
}
}