我们的目标认识只是基础,代码实现是才是核心
1.Huffman树的定义:
从树中一个结点到另一个结点的之间的分支构成两个结点之间的路径,路径上的分支数称为路径长度。那么树的路径长度就是从树根到每一个结点的路径之和。带权路径长度WPL最小的二叉树叫做Huffman树。
二叉树的WPL = 5 * 3 + 15 * 3 + 40 * 2 + 30 * 2 + 10 * 2 = 220
2.Huffman树的构建
这还不是一棵Huffman树,我们需要以下几个步骤
1.先把有权值的叶子结点按照从小到大的顺序排列成一个有序序列:A5,E10,B15,D30,E40.
2.取头两个最小权值的结点作为一个新节点N1的两个子节点,注意我们通常以相对较小的是左孩子,这里A就是N1的左孩子,E为N1的右孩子。新节点的权值为;两个叶子的权值和 5 + 10 = 10.
3.将N1替换成A与E,插入有序序列中,保持从小到大排列。即:N1(15),B15, D30,C40
4.重复2的操作,将N1和B作为一个新节点N2的两个子节点。
5.将N2替换N,与B,插入有序序列中,保持从小到大排列。即: N230, D30C40。
6.重复步骤2。将N2与D作为一个新节点N3的两个子结点。N3的权值=30+30=60。
7.将N3替换N2与D,插入有序序列中,保持从小到大排列。即: C40, N360。
8.重复步骤2。将C与Ngs作为1个新节点T的两个子结点。由于T即是根结点,完成赫夫曼树的构造。
此时带权路径长度 WPL = 40 * 1 + 30 * 2 + 15 * 3 + 10 * 4 +5 * 4 = 205 < 220 huffman树。
Huffman编码只需要把左孩子权值写成0,右孩子写成1,然后从根节点到叶子经过的路径就是它的编码。
A:1000 B:101 C:0 D:11 E:1001
3.代码实现
package datastructure.tree;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Scanner;
public class Huffman {
/** 用来存放节点值 */
private static LinkedList<HuffNode> huffList = new LinkedList<HuffNode>();
public static void main(String[] args) {
//输入数据
System.out.println("先输入数据个数回车,在输入数据");
System.out.println("请输入: ");
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for (int i = 0; i < n; i++) {
//数据输入控制循环
huffList.add(new Huffman().new HuffNode(sc.next(),sc.nextInt() ));
}
huffmanCode();
decode(huffList.get(0), "");
}
class HuffNode implements Comparable<HuffNode> {
/** 权值 */
int value;
String name;
/** 左孩子节点 */
HuffNode lChild = null;
/** 右孩子节点 */
HuffNode rChild = null;
/*
* 构造方法,用于输入初始化Huffman结点
*/
public HuffNode(String name, int value) {
this.value = value;
this.name = name;
}
//构建Huffman树时的构造方法
public HuffNode(HuffNode lChild, HuffNode rChild) {
this.lChild = lChild;
this.rChild = rChild;
// 权值之和,即合并两个叶子节点
this.value = lChild.value + rChild.value;
}
/**********************
* @param next
* @param nextInt
*********************
*/
/**
* 重新写比较方法
*/
public int compareTo(HuffNode o) {
if (this.value < o.value) {
return -1;
} else if (this.value == o.value) {
return 0;
} else {
return 1;
}
}
}
//Huffman树构建和编码
public static void huffmanCode() {
/*
* 当所剩结点为一时构造Huffman树成功
* 否则执行循环直到Huffman树的结点为一结束
*/
if (huffList.size() == 1) {
return ;
}
while (huffList.size() > 1) {
// 排序
Collections.sort(huffList);
// 将前两个节点进行合并
HuffNode node = new Huffman().new HuffNode(huffList.get(0), huffList.get(1));
// 删除前两个节点
huffList.remove();
huffList.remove();
// 将新生成的节点添加到列表中
huffList.add(node);
}
// 编码完成后,此时huffList中只剩一个根节点
}
//解码方法,我们的编码是叶子结点,所以当左右孩子为空时就输出
public static void decode(HuffNode n, String code) {
if ((n.lChild == null) && (n.rChild == null)) {
// 叶子节点, 此时输出其对应编码
System.out.print(n.name + "--->" + code);
System.out.println();
return ;
}
// 遍历左子树
decode(n.lChild, code + "0");
// 遍历右子树
decode(n.rChild, code + "1");
return ;
}
}
测试数据:
5
A 5
B 15
C 40
D 30
E 10
运行结果: