本科时期学习数据结构的时候老师出于大家熟悉所有数据结构的缘由,所有的数据结构都要自己从零开始写。他的出发点是好的,但是实际开发肯定要站在巨人的肩膀上看世界。
以前用的是C++写的,后来也没怎么用过C++了,都是用Java撸码,废话不多说,说一下大体思路。
1. 哈夫曼编码的原理大可以网上查,就是个局部贪心算法,这里不详细说了。
2. 构建三个类,HuffmanNode类,HuffmanTree类和CustomLinkedList类。
贴码:
HuffmanNode.java
public class HuffmanNode{
private HuffmanNode left = null;
private HuffmanNode right = null;
private Integer weight = 0;
private HuffmanNode(int weight,HuffmanNode left,HuffmanNode right){
this.weight = weight;
this.left = left;
this.right = right;
}
public HuffmanNode(int weight){
this(weight, null, null);
}
public HuffmanNode(HuffmanNode left,HuffmanNode right){
this( left.getWeight() + right.getWeight(), left, right);
}
public boolean isLeaf(){
if(null == left && null == right){
return true;
}
return false;
}
public Integer getWeight(){
return weight;
}
public HuffmanNode getLeft(){
return left;
}
public HuffmanNode getRight(){
return right;
}
}
没什么可说的,就是构造方法那里可以看一看。另外还可以写成泛型,我就懒得写了。
CustomLinkedList.java
import java.util.Comparator;
import java.util.LinkedList;
public class CustomLinkedList extends LinkedList {
private Comparator comparator = null;
public void setComparator(Comparator comparator){
this.comparator = comparator;
}
@Override
public boolean add(E e){
int size = this.size();
int index = 0;
while(index
E ei = this.get(index);
if( comparator.compare(ei, e) > 0){//直到遇到一个元素比待插入元素大
this.add(index, e);
return true;
}
++index;
}
return super.add(e);//之前写了this.add(e)害我无限递归,这里标记一下,真是老糊涂了
}
}
这个类主要就是继承LinkedList,好处是每次插入一个元素都能放到排好序的位置。重点在重载的add方法里,认真看一下。LinkedList的好处是在数组中间插入一个元素是快速的,但是get方法定位一个元素就是相对ArrayList是耗时的。还有一个就是要定义比较器Comparator,这里我用了lambda表达式。最后,有强迫症的同学可以用二分法定位,我这样写是看起来很舒服而已。我的遍历的方法耗时O(n),二分法是O(log(n))。
HufmanTree.java
public class HuffmanTree {
private HuffmanNode root = null;
public void buildHuffmanTree(CustomLinkedList cll){
HuffmanNode t1 = null,
t2 = null;
t1 = cll.pollFirst();
t2 = cll.pollFirst();//取出list里头两个元素
while(null != t2){//判断条件是cll中只剩下一个元素,那么树就建好了
//取出list里头的两个元素用于构建一个新的节点
//然后放进list中,这个list自动将新的节点放在合适的位置
cll.add(new HuffmanNode(t1,t2));
t1 = cll.pollFirst();
t2 = cll.pollFirst();//再取出list里头两个元素
}
root = t1;//根节点存根
}
public void travel(){
travelNode(root);
}
private void travelNode(HuffmanNode subRoot){
if(subRoot.isLeaf()){
System.out.println(subRoot.getWeight());
}else{
travelNode(subRoot.getLeft());
travelNode(subRoot.getRight());
}
}
//test huffmanTree
public static void main(String arg[]){
HuffmanTree hfTree = new HuffmanTree();
CustomLinkedList cll = new CustomLinkedList<>();
cll.setComparator((t1,t2)->t1.getWeight().compareTo(t2.getWeight()));
cll.add(new HuffmanNode(42));
cll.add(new HuffmanNode(120));
cll.add(new HuffmanNode(2));
cll.add(new HuffmanNode(37));
cll.add(new HuffmanNode(32));
cll.add(new HuffmanNode(7));
cll.add(new HuffmanNode(42));
cll.add(new HuffmanNode(24));
cll.stream().map(e->e.getWeight())
.forEach(System.out::println);
hfTree.buildHuffmanTree(cll);
hfTree.travel();
}
}
这个类也没什么好说的,就是二叉树的遍历和哈夫曼树构建,哈夫曼树构建的方法buildffmanTree(CustomLinkedList<> cll)就是贪心算法的精髓,看代码还有注释就能明白。