java哈夫曼_Java代码实现哈夫曼编码(Huffman)的方法

package cn.hm;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.ArrayList;

import java.util.Comparator;

import java.util.HashMap;

import java.util.Iterator;

import java.util.PriorityQueue;

import java.util.Set;

public class HFMCondense {

public class HFMNode {

byte data;  //存储字节的数据域

int value;  //字节出现的频率

String code;//叶子结点的哈弗曼编码

HFMNode lchild,rchild;//左右孩子的引用

//只指定数据的构造体

public HFMNode(byte data,int rate){

this(data,rate,null,null);

}

//同时指定左右孩子的构造体

public HFMNode(byte data,int value,HFMNode lchild,HFMNode rchild){

this.data=data;

this.value=value;

this.lchild=lchild;

this.rchild=rchild;

}

}

public static void main(String args[]){

Stringfile="D://tmp//ori.txt";

HFMCondensecondense=newHFMCondense();

HFMNodehfmTree=condense.HashMapToHFMTree(condense.readFiletoMap(file));

condense.HuffmanCoding(hfmTree, "");

System.out.println("开始压缩...");

longstart=System.currentTimeMillis();

condense.CompressFile(condense.createByteArray(condense.FileToString(file)),"D://tmp//des");

System.out.println("压缩结束...用时:"+(System.currentTimeMillis()-start));

}

/**

* 读取将要被压缩的文件,统计每一个字符出现的频率,并将得到的内容存入HashMap中

* @param fileName 将要被压缩的文件

* @return 每一个字节数出现的频率所对应的HashMap

*/

public HashMapreadFiletoMap(String fileName){

HashMaphashMap=newHashMap();

Filefile=newFile(fileName);

if(file.exists()){

try{

InputStreamin=newFileInputStream(file);

//创建与文件大小相同的字节数组

byte[]content=newbyte[in.available()];

//读取文件

in.read(content);

//存入HashMap中

for(inti=0;i

//如果表中存在某一个键

if(hashMap.containsKey(content[i])){

//获取该字节当前的键值

intrate=hashMap.get(content[i]);

//键值增大

rate++;

hashMap.put(content[i], rate);

}

//如果不存在某一个字节对象,则将它存入HashMap当中

else{

hashMap.put(content[i],1);

}

}

in.close();

}catch(Exception e){

e.printStackTrace();

}

}

else{

System.out.println("文件不存在");

}

return hashMap;

}

/**

* 将HashMap中的元素取出来封装到哈弗曼树中,树中叶子结点保存的是HashMap中的每一个键值与频率

* @param map 读取的Map

* @return  哈夫曼树的根结点

*/

public HFMNode HashMapToHFMTree(HashMapmap){

//得到存储键值的系

Setkeys=map.keySet();

//得到迭代器对象

Iteratoriter=keys.iterator();

//如果还有值

while(iter.hasNext()){

bytekey=iter.next();//获取系中的键

intvalue=map.get(key);//得到该键出现的频率

//创建结点并将结点对象加入到队列当中

HFMNodenode=newHFMNode(key,value);

nodeQueue.add(node);

nodeList.add(node);

}

//当所剩的结点数还大于两个

while(nodeQueue.size()>=2){

//得到键值频率最小的两个结点

HFMNodeleft=nodeQueue.poll();

HFMNoderight=nodeQueue.poll();

//将这两个结点组合起来生成新的结点

HFMNodenode=newHFMNode(left.data,left.value+right.value,left,right);

nodeQueue.add(node);

}

//获取队列中的最后一个结点作为根结点

HFMNodehfm=nodeQueue.poll();

return hfm;

}

/**

* 为生成的哈弗曼树进行编码,产生对应的哈弗曼编码表

* @param hfm  对应的哈弗曼树

* @param code 对应生成的哈弗曼编码

* @return 哈弗曼编码表

*/

//创建一个新的哈弗曼编码表

HashMapcodeMap=newHashMap();

public HashMapHuffmanCoding(HFMNode hfm,String code){

//如果左子树不为空,则左子树编码加1

if(hfm.lchild!=null){

HuffmanCoding(hfm.lchild,code+"1");

}

//如果右子树不为空,则右子树编码加0

if(hfm.rchild!=null){

HuffmanCoding(hfm.rchild,code+"0");

}

//如果到达叶子结点,则将元素放入HashMap中生成哈弗曼编码表

if(hfm.lchild==null&&hfm.rchild==null){

codeMap.put(hfm.data,code);

hfm.code=code;

}

return codeMap;

}

/**

* 将哈弗曼编码转换成字符串

* @param fileName 读取的文件名

* @return 编码之后的哈弗曼字符串

*/

public String CodeToString(String fileName){

Filefile=newFile(fileName);

StringcodeString="";

//如果文件存在

if(file.exists()){

try{

InputStreamin=newFileInputStream(file);

byte content[]=new byte[in.available()];

in.read(content);

inti=0;

intlen=content.length;//得到文件的字节长度

intsize=nodeList.size();//得到队列的长度

while(i

for(intj=0;j

if(content[i]==nodeList.get(j).data){

codeString+=nodeList.get(j).code;

break;

}

}

i++;

}

in.close();

}catch(Exception e){

e.printStackTrace();

}

}else {

System.out.println("文件不存在");

}

return codeString;

}

/**

* 将文件按照对应的哈弗曼编码表转成01字符串

* @param fileName 读入的文件名

* @return 转译后的字符串

*/

public String FileToString(String fileName){

Filefile=newFile(fileName);

StringStringContent="";

//如果文件存在

if(file.exists()){

try{

InputStreamin=newFileInputStream(file);

byte content[]=new byte[in.available()];

in.read(content);

//循环转译

intlen=content.length;

for(inti=0;i

StringContent+=codeMap.get(content[i]);

}

in.close();

}catch(Exception e){

e.printStackTrace();

}

}else{

System.out.println("文件不存在");

}

return StringContent;

}

/**

* 将转译后的01字符串重新转换后放入新的字节数组当中

* @param code 转译后的01字符串

* @return 新的字节数组,里面包含了压缩后的字节内容

*/

public byte[] createByteArray(String code) {

//将每8位字符分隔开来得到字节数组的长度

intsize=code.length()/8;

//截取得到字符串8整数后的最后几个字符串

StringdestString=code.substring(size*8);

byte dest[]=destString.getBytes();

//s用来记录字节数组的单字节内容

ints=0;

inti=0;

inttemp=0;

// 将字符数组转换成字节数组,得到字符的字节内容,方便将二进制转为十进制

byte content[] = code.getBytes();

for (intk=0; k

content[k] = (byte) (content[k] - 48);

}

//转译后的字节内容数组

byte byteContent[];

if (content.length %8== 0) {// 如果该字符串正好是8的倍数

byteContent=newbyte[content.length / 8 + 1];

byteContent[byteContent.length - 1] = 0;// 那么返回的字节内容数组的最后一个数就补0

} else {

//否则该数组的最后一个数就是补0的个数

byteContent=newbyte[content.length / 8 + 2];

byteContent[byteContent.length - 1] = (byte) (8 - content.length % 8);

}

intbytelen=byteContent.length;

intcontentcontentlen=content.length;

// byteContent数组中最后一个是补0的个数,实际操作到次后个元素

//Math.pow返回第一个参数的第二个参数次幂的值

while (i

for (intj=0; j

if (content[j] == 1) {// 如果数组content的值为1

s=(int)(s + Math.pow(2, (7 - (j - 8 * i))));// 累积求和

}// if

if ((j+1)%8==0) {// 当有8个元素时

byteContent[i] = (byte) s;// 就将求出的和放入到byteContent数组中去

i++;

s=0;// 并重新使s的值赋为0

}// if

}// for

}// while

intdestdestlen=dest.length;

for(intn=0;n

temp+=(dest[n]-48)*Math.pow(2, 7-n);//求倒数第2个字节的大小

}

byteContent[byteContent.length - 2] = (byte) temp;

return byteContent;

}

/**

* 压缩并输出新文件

* @param content 压缩后产生的新的字节数组

* @param fileName 输出文件名

*/

public void CompressFile(byte[] content,String fileName){

Filefile=null;

//统一后缀名

if(!fileName.endsWith("hfm")){

file=newFile(fileName+".hfm");

}else if(fileName.endsWith("hfm")){

file=newFile(fileName);

}

intlen=content.length;

if(len>0){

try{

OutputStreamout=newFileOutputStream(file);

//将字节内容写入文件

out.write(content);

out.close();

}catch(Exception e){

e.printStackTrace();

}

}else{

System.out.println("压缩出错");

}

}

/**

* 测试一下哈弗曼树建立是否正确

* @param hfm

*/

public void PreOrderTraverse(HFMNode hfm){

if(hfm!=null){

System.out.print(hfm.value+" ");

PreOrderTraverse(hfm.lchild);

PreOrderTraverse(hfm.rchild);

}

}

/**

* 存储哈弗曼树结点的优先队列

*/

ArrayListnodeList=newArrayList();

PriorityQueuenodeQueue=newPriorityQueue(11,new MyComparator());

/**

* 实例化的一个比较器类

*/

class MyComparator implements Comparator{

public int compare(HFMNode o1, HFMNode o2) {

return o1.value-o2.value;

}

}

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值