在二叉树的基础上学习了哈夫曼树,创建哈夫曼树,需要比较数据之间的大小,用到了优先队列的方法,这个方法很好用,可以解决每次取出与放回结点后需要排序的问题。下面跟大家分享下 哈夫曼树的创建及如何取得每个叶子结点的哈夫曼编码。
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Random;
public class hfmList {
private int date[]=new int[256];//定义一个数组,存储每个字节出现的次数
private static hufNode Root=null;//根结点初赋值为空
//函数入口
public static void main(String[] args)throws Exception {
//得到文件路径
hfmList hfm =new hfmList("D:\\temp\\qq.txt");
// hfmList hfm =new hfmList();
hfm.createTree();//调用方法
hfm.getMB(hfm.Root, "");//调用方法
}
//重载构造函数
public hfmList(String path)throws Exception {
//创建文件输入流
FileInputStream fis =new FileInputStream(path);
//将文件转化成缓冲流输入
DataInputStream dis=new DataInputStream(fis);
//读入所有的文件字节
while(dis.available()>0){
int i =dis.read();
date[i]++;//记录每个字节出现的频率
}
}
/**
* 使用优先队列构造哈弗曼树
*/
public void createTree(){
PriorityQueue<hufNode> nodeQueue = new PriorityQueue<hufNode>();
//将所有的结点都加入到队列中去
for(int i=0;i <date.length;i++){
if(date[i] !=0){//字节次数不为零
//取出结点
hufNode node =new hufNode(i,date[i]);
//将结点添加到队列中
boolean no=nodeQueue.add(node);
System.out.println(no);//调试加入是否成功
}
}
//构建哈弗曼树
while (nodeQueue.size() > 1){
hufNode min1 = nodeQueue.poll();//获取队列头
hufNode min2 = nodeQueue.poll();//获取队列的第二个数
//将获取的队列的前两个结点相加构成一个新结点
hufNode result =new hufNode(0,min1.times+min2.times);
//设置三个结点间的关系
result.leftchild =min1;
result.rightchild =min2;
min1.parent=result;
min2.parent=result;
nodeQueue.add(result);//加入合并结点
}
Root=nodeQueue.peek();//得到根结点
}
//取得每个叶子结点的哈夫曼编码
public void getMB(hufNode root,String s){
if((root.leftchild == null)&& (root.rightchild==null)){//得到叶结点
Code hc =new Code();
hc.node=s;
hc.n=s.length();
System.out.println("结点"+root.date+"编码"+hc.node);
}
if(root.leftchild !=null){//如果不为空,则左 0 右1
getMB(root.leftchild,s+'0');
}
if(root.rightchild !=null){
getMB(root.rightchild,s+'1');
}
}
}
还需要一个结点类,我将结点类设置为哈夫曼类的内部类
//创建结点类
class hufNode implements Comparable{
int times;//结点的数据对象
int date;//结点出现有频率
hufNode parent;//定义父亲结点
hufNode leftchild=null;//左结点初赋值为空
hufNode rightchild =null;//右结点初赋值为空
//构造函数,用于传递参数
public hufNode(int times,int date){
this.times=times;
this.date=date;
}
//重写方法,比较两个对象
public int compareTo(Object o) {
hufNode huf =(hufNode)o;
return times-huf.times;//根据返回值是正数、零或负数来判断两个对象的大小
}
}
另外还要创建编码长度的类.本来可以不用再创建这个类的,只是这样做的话,显得条理更清晰些。
public class Code {
String node;//编码
int n;//编码的长度
}
这样,我们的哈夫曼树建好啦。当然在此基础上还有很大的改进空间,任重道远啊……