Java哈夫曼树与文件压缩和解压缩

6 篇文章 0 订阅

之前看到一篇文章,博主给出了压缩文件:https://blog.csdn.net/bluesky_usc/article/details/54185106

在这基础上,添加了对文件进行了解压的方法:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Queue;
import java.util.*;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.LinkedList;

public class Main {

    public static void main(String[] args) throws Exception {
        //创建压缩对象
        Compress compress = new Compress();
        //统计文件中0-255出现的次数
        compress.countTimes("F:\\test.txt");
        //构造哈夫曼树,并得到根节点
        HuffmNode root=compress.createTree();
        //得到哈夫曼编码
        compress.getHuffmCode(root, "");
        //压缩文件
        compress.compress("F:\\test.txt",
                "F:\\test.zip");
        compress.Decode("F:\\test.zip" , root);        //解压
        System.out.println(Compress.breath(root));
    }
}



/****/

 class HuffmNode {
    //数据域
    private int data;
    //索引
    private int index;
    //左子节点
    private HuffmNode left;
    //右子节点
    private HuffmNode right;

    //哈夫曼节点的构造函数
    public HuffmNode(int data,int index){
        this.data=data;
        this.index=index;
    }

    //私有属性的封装
    public int getData() {
        return data;
    }
    public void setData(int data) {
        this.data = data;
    }
    public int getIndex() {
        return index;
    }
    public void setIndex(int index) {
        this.index = index;
    }
    public HuffmNode getLeft() {
        return left;
    }
    public void setLeft(HuffmNode left) {
        this.left = left;
    }
    public HuffmNode getRight() {
        return right;
    }
    public void setRight(HuffmNode right) {
        this.right = right;
    }


    public String toString() {
        // TODO Auto-generated method stub
        int num = 0;
        if(index != -1)
            return "data:" + ((char)this.getIndex()+"") + ",weight:" + this.getData() + ";   ";

        return "data:" + ((char)this.getIndex()+"") + ",weight:" + this.getData()+ ";   ";
    }

}


class Compress {

    public static int [] times = new int[256];
    public String [] HuffmCodes=new String[256];
    public LinkedList<HuffmNode> list = new LinkedList<HuffmNode>();
    //统计次数

    //初始化
    public Compress(){
        for (int i = 0; i < HuffmCodes.length; i++) {
            HuffmCodes[i]="";
        }
    }

    public void countTimes(String path) throws Exception{
        //构造文件输入流
        FileInputStream fis = new FileInputStream(path);
        //读取文件
        int value=fis.read();
        while(value!=-1){
            times[value]++;
            value=fis.read();
        }
        //关闭流
        fis.close();
    }

    //构造哈夫曼树
    public HuffmNode createTree(){
        //将次数作为权值构造森林
        for (int i = 0; i < times.length; i++) {
            if(times[i]!=0){
                HuffmNode node = new HuffmNode(times[i],i);
                //将构造好的节点加入到容器中的正确位置
                list.add(getIndex(node), node);
            }
        }

        //将森林(容器中的各个节点)构造成哈夫曼树
        while(list.size()>1) {
            //获取容器中第一个元素(权值最小的节点)
            HuffmNode firstNode =list.removeFirst();
            //获取中新的第一个元素,原来的第一个元素已经被移除了(权值次小的节点)
            HuffmNode secondNode =list.removeFirst();
            //将权值最小的两个节点构造成父节点
            HuffmNode fatherNode =
                    new HuffmNode(firstNode.getData()+secondNode.getData(),-1);
            fatherNode.setLeft(firstNode);
            fatherNode.setRight(secondNode);
            //父节点加入到容器中的正确位置
            list.add(getIndex(fatherNode),fatherNode);
        }
        //返回整颗树的根节点
        return list.getFirst();
    }
    //利用前序遍历获取编码表
    public void getHuffmCode(HuffmNode root,String code){
        //往左走,哈夫曼编码加0
        if(root.getLeft()!=null){
            getHuffmCode(root.getLeft(),code+"0");
        }
        //往右走,哈夫曼编码加1
        if(root.getRight()!=null){
            getHuffmCode(root.getRight(),code+"1");
        }
        //如果是叶子节点,返回该叶子节点的哈夫曼编码
        if(root.getLeft()==null && root.getRight()==null){
//          System.out.println(root.getIndex()+"的编码为:"+code);
            HuffmCodes[root.getIndex()]=code;
        }
    }

    //压缩文件
    public void compress(String path,String destpath) throws Exception{



        //构建文件输出流
        FileOutputStream fos = new FileOutputStream(destpath);
        FileInputStream fis = new FileInputStream(path);

        /**===============将数据写入到文件中================*/

        //读文件,并将对应的哈夫曼编码串接成字符串
        int value=fis.read();
        String str = "";
        while(value!=-1){
            str+=HuffmCodes[value];
//          System.out.println((char)value+":"+str);
            value=fis.read();
        }
        System.out.println(str);
        fis.close();

        String s="";
        while(str.length()>=8){
            s=str.substring(0, 8);
            int b=changeStringToInt(s);
//              System.out.println(c);
            fos.write(b);
            fos.flush();
            str=str.substring(8);
        }

        int last1=8-str.length();
        for (int i = 0; i <last1; i++) {
            str+="0";
        }
        s=str.substring(0, 8);
//          System.out.println(s);
        int d=changeStringToInt(s);
        fos.write(d);

//          补0
        fos.write(last1);
          fos.flush();

        fos.close();

    }
    //解压缩
    public void Decode(String path ,HuffmNode root) throws Exception {
        FileInputStream fis = new FileInputStream(path);
        int value=fis.read();
        int last_num = 0;
        String str = "";
        String last_str = "";
        String b = new String("");
        while(value!=-1){
            Integer a = new Integer(value);

            last_str = str;
            str +=  addZeroForNum(Integer.toBinaryString(a),8);

            last_num = value;
//          System.out.println((char)value+":"+str);
            value=fis.read();

        }
        str = last_str;
        str = str.substring(0,str.length() - last_num);
        System.out.println(str);

        int num = 0;
        int a = (int)(str.charAt(num)-48);
        HuffmNode node = null,last_node;
        last_node = root;
        String os = "";
        while(str.length() > 0){
            while(true) {
                if ((int) (str.charAt(num) - 48) == 0) {
                    node = last_node.getLeft();
                    if(node == null){ break;}
                }
                if ((int) (str.charAt(num) - 48) == 1) {
                    node = last_node.getRight();
                    if(node == null){ break;}
                }
                last_node = node;
                num++;
                if(num > str.length() - 1)
                    break;
            }
            os += ((char)last_node.getIndex() + "");
            str = str.substring(num);
            num = 0;
            last_node = root;
        }
        System.out.println(os);
    }


    public static String addZeroForNum(String str,int strLength) {
        int strLen =str.length();
        if (strLen <strLength) {
            while (strLen< strLength) {
                StringBuffer sb = new StringBuffer();
                sb.append("0").append(str);//左补0
//    sb.append(str).append("0");//右补0
                str= sb.toString();
                strLen= str.length();
            }
        }

        return str;
    }

    //插入元素位置的索引
    public int getIndex(HuffmNode node) {
        for (int i = 0; i < list.size(); i++) {
            if(node.getData()<=list.get(i).getData()){
                return i;
            }
        }
        return list.size();
    }

    //将字符串转换成整数
    public int changeStringToInt(String s){
        int v1=(s.charAt(0)-48)*128;
        int v2=(s.charAt(1)-48)*64;
        int v3=(s.charAt(2)-48)*32;
        int v4=(s.charAt(3)-48)*16;
        int v5=(s.charAt(4)-48)*8;
        int v6=(s.charAt(5)-48)*4;
        int v7=(s.charAt(6)-48)*2;
        int v8=(s.charAt(7)-48)*1;
        return v1+v2+v3+v4+v5+v6+v7+v8;

    }

    public static <T> List<HuffmNode> breath(HuffmNode root) {
        List<HuffmNode> list = new ArrayList<HuffmNode>();
        Queue<HuffmNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            HuffmNode pNode = queue.poll();
            list.add(pNode);
            if (pNode.getLeft() != null) {
                queue.add(pNode.getLeft());
            }
            if (pNode.getRight() != null) {
                queue.add(pNode.getRight());
            }
        }
        return list;
    }
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值