接下来学习了哈夫曼树,总结一下哈夫曼树:
了解Huffman算法之前,我们先介绍一下一颗树的构造价值:
构造价值指的是,在一个树当中,如果有n层,那么每层的系数为1、2、3……n,然后吧每个叶子节点的构造价值乘以系数,总和就是这棵树的构造总价值,这也就叫做哈夫曼树的构造价值,我们看一个例子:
对于这一棵树,我们计算一下他的哈夫曼构造价值:
这里叶子节点一共有3个:6和13和17
所以价值等于6*2 + 13 *3 + 17 *3 = 102
同样是这3个叶子节点,我们换一种树的构造法:
这种情况下,哈夫曼构造价值 = 17*2 + 6*3 + 13*3 = 91.构造价值比上一种要小。
所以我们发现,只要把数值大的叶子节点,放在更低的层次,就可以使总构造价值更小。这就是哈夫曼树,那么如何构造这棵树呢?
哈夫曼树、哈夫曼编码之类的都是一个思想,就是使用贪心法,每次都选取当前最小的两个树加起来,最后吧所有的东西构造成一课树。
我们用一组数据来举例子:
假如有这么6个节点,每个节点有一定的构造价值
那么就有对应的两个数组:
int f[] = { 45 , 13 , 12 , 16 , 9 , 5 };
char d[] = {‘a’ ,‘b’, ‘c’, ‘d’, ‘e’, ‘f’ };
我们首先解决一下这个问题的先决条件,构造一颗树,但是二叉树(BinaryTree)在api中没有显式的定义,需要我们自己定义。下面写一下这里的需要用到的树的功能:这里的树重写了comparable接口的compareto方法,用来后续的键值比较
public class BinaryTree implements Comparable<BinaryTree>{
int key;
char data;
BinaryTree left;
BinaryTree right;
public BinaryTree() {
// TODO 自动生成的构造函数存根
}
public BinaryTree(int k, char d, BinaryTree l, BinaryTree r) {
this.key = k;
this.data = d;
this.left = l;
this.right = r;
}
public String toString() {
return data+"," + key + ";";
}
@Override
public int compareTo(BinaryTree x) {
// TODO 自动生成的方法存根
if (key < x.key) {
return -1;
}
if (key > x.key) {
return 1;
}
return 0;
}
//中序遍历
public void inOrder() {
if (left != null) {
left.inOrder();
}
System.out.println(toString());
if (right != null) {
right.inOrder();
}
}
}
接下来我们实现哈夫曼树的构造:
思路是这样的,我们选最小的两片叶子,然后吧他合并起来的值当成一个新的叶子,加进里面,然后再选两个最小的值合并起来,然后重复知道最后只有两个值,然后合并,就构造成了一颗树,如图:
先选5和9,拼成一个14的树
然后选12和13,评成25的树
然后选14和16,评成30
再选25和30,评成一个65的树
最后吧45和55拼起来,就构成了哈夫曼树:
代码解决方案:在java里有一个东西叫做优先队列(PriorityQueue),优先队列可以理解为一个可以排序的队列,优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序,具体取决于所使用的构造方法。详见api文档搜索PriorityQueue
通过优先队列,我们把数据都放进去,然后通过优先队列来取数,这样就可以保证每次取得最小的两个,然后我们在构造成一颗树,下面看代码:
public class BinaryTree implements Comparable<BinaryTree>{
int key;
char data;
BinaryTree left;
BinaryTree right;
public BinaryTree() {
// TODO 自动生成的构造函数存根
}
public BinaryTree(int k, char d, BinaryTree l, BinaryTree r) {
this.key = k;
this.data = d;
this.left = l;
this.right = r;
}
public String toString() {
return data+"," + key + ";";
}
@Override
public int compareTo(BinaryTree x) {
// TODO 自动生成的方法存根
if (key < x.key) {
return -1;
}
if (key > x.key) {
return 1;
}
return 0;
}
//中序遍历
public void inOrder() {
if (left != null) {
left.inOrder();
}
System.out.println(toString());
if (right != null) {
right.inOrder();
}
}
}