哈夫曼树(最优二叉树)Huffman的原理建立及遍历Java实现
哈夫曼树(Huffman)又称最优树,是一类带权路径长度最短的树。树的带权路径长度为树中所有叶子结点的带权路径长度之和,记为WPL。其中WPL最小的树称最优二叉树或是哈夫曼树。
例子:有4个权值(1,3,5,7),利用这4个权值作为叶子结点构造二叉树。
在图示的三个二叉树中:
wp1 = 12+32+52+72 = 32
wp2 = 13+33+52+71 = 29
wp3 = 12+33+53+71 = 33
上例的结果说明,由相同权值的一组叶子结点所构成的二叉树有不同的形态和不同的带权路径
如何构造带权路径长度最小的二叉树,哈夫曼给出了答案,这就是著名的哈夫曼树。
构造哈夫曼树其实也是树的一种方法,运用递归不断构造其步骤如下:
1.对给定乱序的权值排序,使其成为有序的数组。
2对这有序的数组取出最小两个值,生成新的一个结点,新结点的值为前两个值之和,并删除这两结点。
3.重复上面两步知道只有一个值时结束。
建立二叉树及遍历代码如下:
package demo;
public class Node implements Comparable<Node>{
private int value;
private Node left;
private Node right;
public Node(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
@Override
public int compareTo(Node o) {
return o.value-this.value;
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
}
package demo;
import java.util.*;
/**
* huffman的建立及遍历
*/
public class TestHuffmanTree {
public static void main(String[] args) {
//定义一个数组权值
int[] arr = {3,7,8,29,5,11,23,14};
//创建一个哈夫曼函数创建树
Node node = createHuffmanTree(arr);
// System.out.println(node);
//对哈夫曼树一层层遍历利用队列
TestHuffmanTree.levelDisplay(node);
}
/**
* 建立huffman树
* @param arr
* @return
*/
private static Node createHuffmanTree(int[] arr) {
//先使用数组中所有元素创建若干个二叉树,(只有一个结点)
List<Node> nodes = new ArrayList<>();
//List<Node> list = new ArrayList<>();
//存入到nodes集合里
for (int value:arr) {
nodes.add(new Node(value));
}
//System.out.println(nodes);
//循环处理
while (nodes.size()>1){
//排序
Collections.sort(nodes);
//取出权值最小的两颗二叉树
Node left = nodes.get(nodes.size()-1);
Node right = nodes.get(nodes.size()-2);
//创建一个新的二叉树
Node parent = new Node(left.getValue()+right.getValue());//也可以left.value/right.value去掉private
parent.setLeft(left);
parent.setRight(right);
//把取出来的两个二叉树移除
nodes.remove(left);
nodes.remove(right);
//放入原来的二叉树集合中
nodes.add(parent);
}
return nodes.get(0);
}
/**
* 使用队列实现层次遍历
* @param root
*/
public static void levelDisplay(Node root) {
List<Node> list = new ArrayList<>();
Queue<Node> queue = new LinkedList<>();
queue.add(root);
//层次遍历队列
while (!queue.isEmpty()) {
Node pNode = queue.poll();
System.out.println(pNode.toString());
if (pNode.getLeft() != null) {
queue.add(pNode.getLeft());
}
if (pNode.getRight() != null) {
queue.add(pNode.getRight());
}
}
}
}
哈夫曼编码部分原理,及代码,由于涉及的少没有具体去实现,请参考其他博客。