什么是哈夫曼二叉树?
哈夫曼树又叫做最优树。什么是最优?路径(权值)最短。
/*
* 1、统计学生学分
* 学生考试结果 A B C D
* 学分增加 5 4 3 0
* 人数 10 50 30 10
*
* 代码1:
* if A : +5
* else if B : +4
* else if C : +3
* else D :0
* 判断需要经过 = 10 + 50*2 +30*3 +10*3 (次)
* 代码2:
* if B :+4
* else if C:+3
* else if A: +5
* else D : 0
* 判断需要经过 = 50 + 30 *2 +(10+10)*3 (次)
代码2的时间明显优于代码1.这里的人数可以看作为权值,也就是说权值最大的放置在最上面,权值最小的放在树的最小面。于是可以得出类似的数
* B
* +4 C
* +3 A
* +5 +0
构建哈夫曼二叉树
从最优算法中可以类似得到的:
1.权值:出现的次数
2.路径长度:当前节点到根节点的层数
3.加权路径:该结点到根节点之间的路径(长度)和权值的乘积
4.二叉树的路径长度:由根结点到所有叶子结点的路径长度之和
哈夫曼二叉树就是所有节点的加权路径之和最小的树。这就是最优树。
了解这些以后就可以开始构建哈夫曼二叉树了。
**第一步:统计字符串中各个字母出现次数,并且生成节点
第二步:根据节点的权值排序
第三步:取出权限最小的两个节点,构建一个新节点
第四步:重复2 3,直到只剩一个节点,该节点就是根节点。**
代码部分:
1.结点类
这部分就是给结点声明几个属性,再设置get和set方法为了方便操作。
public class Node {
private Object data;//数据
private Node left;//左节点
private Node right;//右节点
private int weight;//权值
public Node(){
}
public Node(Object data,int weight){
super();
this.data = data;
this.weight = weight;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
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;
}
}
哈夫曼二叉树类
需要注意的是,每进行一次新节点的生成之后,都要进行一次排序比较每个结点的权值,有的时候生成的结点会大于其他节点,如下图,但这是错误的!生成ab之后应该再比较c和d。
每次重新排序后
public class HalfmenTree<E> {
private Node root;
private int[] num = new int[128];// 权值数组
// 声明一个队列存字符的Ascll码对象
ArrayList<Object> numlist = new ArrayList<Object>();
// 声明一个队列存贮节点
ArrayList<Node> list = new ArrayList<Node>();
// 根据字母的权值排序从小到大(冒泡排序)
public void sort(){
for (int i = 0; i < list.size(); i++) {
for (int j = i + 1; j < list.size(); j++) {
if (list.get(i).getWeight() > list.get(j).getWeight()) {
Node node = list.get(i);
list.set(i, list.get(j));
list.set(j, node);
}
}
}
}
public void add(String str) {
// 将str拆成单个字符,并根据其对应的Ascll码存放在num权值数组中
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
int n = (int) ch;
num[n]++;
if (num[n] == 1) {// 当每个字母第一次出现时,将这个字母的Ascll码存进numlist
numlist.add(n);
}
}
// 生成节点
for (int i = 0; i < numlist.size(); i++) {
int n = (int) numlist.get(i);
int m = num[n];
char ch = (char) n;
Node node = new Node(ch, m);
list.add(node);
}
// 根据字母的权值排序从小到大(冒泡排序)
sort();
// 排序后输出节点的字母和权值
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getData() + " " + list.get(i).getWeight());
}
System.out.println("=======================");
// 取出权值最小的两个节点,构建一个新节点
while (list.size() > 1) {
Node left = list.remove(0);
Node right = list.remove(0);
String st = left.getData().toString() + right.getData().toString();//st为左右子节点的字母并在一起
Node father = new Node(st, left.getWeight() + right.getWeight());
father.setLeft(left);
father.setRight(right);
list.add(0, father);
sort();//排序
}
// 让根节点等于最后一个节点
root = list.get(0);
}
public void output() {
output(root);
}
/**
* 递归遍历
*/
public void output(Node node) {
//后序遍历
if (node.getLeft() != null) {
output(node.getLeft());
if (node.getRight() != null) {
output(node.getRight());
}
}
System.out.println(node.getData() + " " + node.getWeight());
}
}
3.测试类随便发挥
public class Manage2 {
public static void main(String[] args) {
HalfmenTree ht = new HalfmenTree();
ht.add("sadadsadaaqweqeadad");
ht.output();
}
}