哈夫曼树又叫最优二叉树,是一类带权路径最短的二叉树。哈夫曼树是二叉树的一种应用,在信息检索中很常用。
哈夫曼树可以用来解决报文编码问题,在通信领域有着非常广泛的运用。具体什么是带权路径二叉树,什么是哈夫曼编码这里不做介绍,这里只介绍代码,必须先知道这些概念才能阅读代码!
以下为全部代码,做了比较详细的注释,所以不做另外解释
节点类:
package huffman_binary_tree;
//树结点
public class Node {
private String data;
private Node leftNode;
private Node rightNode;
//结点的权值
private double weight;
public Node(String data,double weight){
this.data=data;
this.weight=weight;
}
public Node getLeftNode() {
return leftNode;
}
public void setLeftNode(Node leftNode) {
this.leftNode = leftNode;
}
public Node getRightNode() {
return rightNode;
}
public void setRightNode(Node rightNode) {
this.rightNode = rightNode;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "Node[data="+data+",weight="+weight+"]";
}
}
哈夫曼树具体实现类:
package huffman_binary_tree;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
//哈夫曼树
public class HuffmanTree {
/**
* 节点集合
*/
private List<Node> nodes=new ArrayList<Node>();
/**
* 添加结点
* @param node
* @return
*/
public HuffmanTree addNode(Node node){
nodes.add(node);
return this;
}
/**
* 快速排序
*/
private void quickSort(){
sort(0,nodes.size()-1);
}
/**
* 快速排序的具体实现过程
* @param start
* @param end
*/
private void sort(int start,int end){
if(start<end){
double temp=nodes.get(start).getWeight();
int i=start;
int j=end+1;
while(true){
while(i<end&&nodes.get(++i).getWeight()<=temp);
while(j>start&&nodes.get(--j).getWeight()>=temp);
if(i<j){
swap(i,j);
}else{
break;
}
}
swap(start,j);
sort(start,j-1);
sort(j+1,end);
}
}
/**
* 结点交换
* @param i
* @param j
*/
private void swap(int i,int j){
Node temp;
temp=nodes.get(i);
nodes.set(i, nodes.get(j));
nodes.set(j, temp);
}
/**
* 生成哈夫曼树,返回根结点
* @return
*/
public Node crreateHuffmanTree(){
//当结点集合中只有一个结点(即根结点)时结束
while(nodes.size()>1){
//对当前结合中的结点进行排序(结点集合中的结点个数每次都会改变)
quickSort();
//取到两个权值最小的结点
Node left=nodes.get(0);
Node right=nodes.get(1);
//新结点
Node newNode=new Node(null,left.getWeight()+right.getWeight());
newNode.setLeftNode(left);
newNode.setRightNode(right);
//移除两个最小的结点
nodes.remove(0);
nodes.remove(0);
//添加新结点
nodes.add(newNode);
}
//返回根结点
return nodes.get(0);
}
//广度优先遍历(需要借助队列)
public List<Node> breadthFirst(Node root){
//保存结果集
List<Node> lists=new ArrayList<Node>();
//队列
Queue<Node> queue=new ArrayDeque<Node>();
if(root!=null){
//加入结点到队列中
queue.offer(root);
}
//如果队列为空,则结束
while(!queue.isEmpty()){
//peek方法不移除结点
lists.add(queue.peek());
//弹出且移除
Node p=queue.poll();
//如果左结点不为空,则加入队列
if(p.getLeftNode()!=null){
queue.offer(p.getLeftNode());
}
//如果右结点不为空,则加入队列
if(p.getRightNode()!=null){
queue.offer(p.getRightNode());
}
}
return lists;
}
}
哈夫曼编码实现类:
package huffman_binary_tree;
import java.util.HashMap;
import java.util.Map;
public class HuffmanCoding {
Map<String,String> map=new HashMap<String,String>();
public Map<String,String> coding(Node root){
process(root,"");
return map;
}
private void process(Node node,String content){
//叶子结点
if(node.getLeftNode()==null){
map.put(node.getData(), content);
return;
}
//对左子树分配代码"0"
process(node.getLeftNode(),content+"0");
//对右子树分配代码"1"
process(node.getRightNode(),content+"1");
}
}
测试类:
package huffman_binary_tree;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
//最优二叉树,哈夫曼树
public class Main {
public static void main(String[] args) {
HuffmanTree tree=new HuffmanTree();
tree.addNode(new Node("A",40.0))
.addNode(new Node("B",8.0))
.addNode(new Node("C",10.0))
.addNode(new Node("D",30.0))
.addNode(new Node("E",10.0))
.addNode(new Node("F",2.0));
Node root=tree.crreateHuffmanTree();
//广度遍历
// List<Node> lists=tree.breadthFirst(root);
// for(Node node:lists){
// System.out.println(node);
// }
HuffmanCoding coding=new HuffmanCoding();
Map<String,String> map=coding.coding(root);
Set<String> mapSet=map.keySet();
//TreeSet实现排序
TreeSet<String> set=new TreeSet<String>(mapSet);
Iterator<String> iterator=set.iterator();
while(iterator.hasNext()){
String str=iterator.next();
System.out.println(str+":"+map.get(str));
}
}
}
输出结果:
A:0
B:1101
C:1110
D:10
E:1111
F:1100