哈弗曼树的理解和实现(Java)
哈弗曼树概述
哈弗曼树又称最优树,是一种带权路径长度最短的树,在实际中有广泛的用途。哈弗曼树的定义,涉及路径、路径长度、权等概念。哈弗曼树可以用于哈弗曼编码,用于压缩,用于密码学等。
哈弗曼树的一些定义
路径:从树中的一个结点到另一个结点之间的分支构成这两个结点的路径,
路径长度:路径上的分支数目称为路径长度。
树的路径长度:从树根到每一个结点的路径长度之和,我们所说的完全二叉树就是这种路径长度最短的二叉树。
权:赋予某个实体一个量,是对实体的某个或某些属性的数值化描述。
节点的带权路径长度:从该节点到树根之间的路径长度与节点上权的乘积。
树的带权路径长度:如果在树的每一个叶子结点上赋上一个权值,那么树的带权路径长度就等于根结点到所有叶子结点的路径长度与叶子结点权值乘积的总和。
最优二叉树:从已给出的目标带权结点(单独的结点) 经过一种方式的组合形成一棵树.使树的权值最小.。最优二叉树是带权路径长度最短的二叉树。根据结点的个数,权值的不同,最优二叉树的形状也各不相同。它们的共同点是:带权值的结点都是叶子结点。权值越小的结点,其到根结点的路径越长。
他们的带权长度分别为:
WPL1:7*2+5*2+2*2+4*2=36
WPL2:7*3+5*3+2*1+4*2=46
WPL3:7*1+5*2+2*3+4*3=35
所以,第三棵树的带权路径最短。
构造哈弗曼树
1) 根据给定的n个权值{w1, w2, w3, w4......wn}构造n棵只有根节点的二叉树,这n棵二叉树构成一个森林F。
2) 在森林F中选择两棵根节点的权值最小的二叉树,作为一棵新的二叉树的左右子树,且令新的二叉树的根节点的权值为其左右子树的权值和;
3)从F中删除被选中的那两棵子树,并且把构成的新的二叉树加到F森林中;
4)重复2 ,3 操作,直到森林只含有一棵二叉树为止,此时得到的这棵二叉树就是哈夫曼树。
代码实现(Java)
节点类:
package 哈弗曼树;
public class HuffmanNode {
private Object data;
private int weight;
private HuffmanNode lChild;
private HuffmanNode rChild;
public HuffmanNode() {
this.data = null;
this.weight = 0;
this.lChild = null;
this.rChild = null;
}
public HuffmanNode(Object data, int weight) {
this.data = data;
this.weight = weight;
}
public HuffmanNode(int weight, HuffmanNode lChild, HuffmanNode rChild) {
this.weight = weight;
this.lChild = lChild;
this.rChild = rChild;
}
public HuffmanNode(Object data, int weight, HuffmanNode lChild, HuffmanNode rChild) {
this.data = data;
this.weight = weight;
this.lChild = lChild;
this.rChild = rChild;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public HuffmanNode getlChild() {
return this.lChild;
}
public void setlChild(HuffmanNode lChild) {
this.lChild = lChild;
}
public HuffmanNode getrChild() {
return this.rChild;
}
public void setrChild(HuffmanNode rChild) {
this.rChild = rChild;
}
}
哈弗曼树类:
package 哈弗曼树;
import java.util.ArrayList;
public class HuffmanTree {
private String str = "";
private HuffmanNode root;
private ArrayList<String> charList;
private ArrayList<HuffmanNode> nodeList;
private boolean flag;
//构造哈弗曼树
public void createHuffmanTree(String str) {
this.str = str;
charList = new ArrayList<String>();
nodeList = new ArrayList<HuffmanNode>();
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
flag = true;
for (int j = 0; j < charList.size(); j++) {
if(charList.get(j).charAt(0) == ch) {
String s = charList.get(j) + ch;
charList.set(j, s);
flag = false;
break;
}
}
if(flag) {
charList.add(charList.size(), ch + "");
}
}
for (int i = 0; i < charList.size(); i++) {
Object data = charList.get(i).charAt(0);
int weight = charList.get(i).length();
HuffmanNode node = new HuffmanNode(data, weight);
nodeList.add(node);
}
while(nodeList.size() > 1) {
this.sortOrder(nodeList);
HuffmanNode left = nodeList.remove(0);
HuffmanNode right = nodeList.remove(0);
int parentWeight = left.getWeight() + right.getWeight();
HuffmanNode parent = new HuffmanNode(null, parentWeight, left, right);
nodeList.add(parent);
}
root = nodeList.get(0);
}
//升序排序
private void sortOrder(ArrayList<HuffmanNode> nodeList) {
for (int i = 0; i < nodeList.size() - 1; i++) {
for (int j = i + 1; j < nodeList.size(); j++) {
HuffmanNode node;
if(nodeList.get(i).getWeight() > nodeList.get(j).getWeight()) {
node = nodeList.get(i);
nodeList.set(i, nodeList.get(j));
nodeList.set(j, node);
}
}
}
}
//中序遍历二叉树
public void print() {
output(root);
}
private void output(HuffmanNode root) {
if(root != null) {
System.out.print(root.getData() + " , ");
output(root.getlChild());
output(root.getrChild());
}
}
public static void main(String[] args) {
HuffmanTree tree = new HuffmanTree();
tree.createHuffmanTree("aabbbcccc");
tree.print();
}
}