0 引出
- 给定 n 个权值作为 n 个叶子结点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)
- 路径长度:若规定根结点的层数为 1,则从根结点到第 L 层结点的路径长度为 L-1
- 结点的权及带权路径长度:若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积
- 树的带权路径长度:树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为 WPL(weighted pathlength) ,权值越大的结点离根结点越近的二叉树才是最优二叉树。
1 思路
- 整体实现思路:实现权值大的叶子节点靠近根节点,而权值小的叶子远离根节点
- 想实现第一步,我们就从下往上构建赫夫曼树,按权值升序将n个叶子节点排序,取出最小两个叶子节点(权值为p和q),创建其父节点(权值为p+q),再将该父节点和剩余的(n-2)个叶子节点比较,取出最小两个,重复刚才的操作直到不再有剩余的叶子节点
2 代码实现
public class App02_HuffmanTree {
public static void main(String[] args) {
int[] arr = {13, 7, 8, 3, 29, 6, 1};
Node01 root = createHuffmanTree(arr);
if (root != null) {
root.preOrder();
} else {
System.out.println("树为空!!!");
}
}
public static Node01 createHuffmanTree(int[] arr) {
ArrayList<Node01> list = new ArrayList<>();
for (int value : arr) {
list.add(new Node01(value));
}
while (list.size() > 1) {
Collections.sort(list);
Node01 left = list.get(0);
Node01 right = list.get(1);
Node01 parent = new Node01(left.getValue() + right.getValue());
parent.setLeft(left);
parent.setRight(right);
list.remove(left);
list.remove(right);
list.add(parent);
}
return list.get(0);
}
}
class Node01 implements Comparable<Node01>{
private int value;
private Node01 left;
private Node01 right;
public Node01(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node01 getLeft() {
return left;
}
public void setLeft(Node01 left) {
this.left = left;
}
public Node01 getRight() {
return right;
}
public void setRight(Node01 right) {
this.right = right;
}
@Override
public String toString() {
return "Node01 [value=" + value + "]";
}
@Override
public int compareTo(Node01 Node01) {
return this.value-Node01.value;
}
public void preOrder() {
System.out.println(this);
if (this.left != null) {
left.preOrder();
}
if (this.right != null) {
right.preOrder();
}
}
}