算法:Huffman编码实现数据压缩以及解压

//huffman树节点类
class HCNode implements Comparable<HCNode>{
    Byte data;     //数据(字符)
    int weight;    //权重(字符出现次数)
    HCNode left;
    HCNode right;
    public HCNode(Byte data,int weight){
        this.data=data;
        this.weight=weight;
    }
    @Override
    public int compareTo(HCNode o) {
        return weight-o.weight;
    }

    @Override
    public String toString() {
        return "HCNode{" +
                "data=" + data +
                ", weight=" + weight +
                '}';
    }
}

//简单写了
//解压文件
public static void unZipFile(String zipFile,String dst)throws IOException,ClassNotFoundException{
        ObjectInputStream in=new ObjectInputStream(new FileInputStream(zipFile));
        FileOutputStream out=new FileOutputStream(dst);
        byte[] zipDatas=(byte[]) in.readObject();
        Map<Byte,String> huffmanEn= (Map<Byte, String>) in.readObject();
        byte[] datas=decode(zipDatas,huffmanEn);
        out.write(datas);
        System.out.println("解压成功");
    }

//压缩文件
    public static void zipFile(String src,String dst){
        FileInputStream in=null;
        ObjectOutputStream out=null;
        try {
            in=new FileInputStream(src);
            out=new ObjectOutputStream(new FileOutputStream(dst));
            byte[] datas=new byte[in.available()];
            in.read(datas);
            byte[] zipDatas=huffmanZip(datas);
            out.writeObject(zipDatas);
            out.writeObject(encodingTable);
            System.out.println("压缩成功");
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if(in!=null){
                try {
                    in.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
            if(out!=null){
                try {
                    out.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }

public static Map<Byte,String> encodingTable=new HashMap<>(); //huffman编码表
public static String last;     //记录原数据经过编码后得到的二进制串中最后不足八位的串

//arr 要压缩的字节数据
//将arr转为Huffman树的叶子节点的集合
public static List<HCNode> getNodes(byte[] arr){
        List<HCNode> nodes=new ArrayList<>();
        Map<Byte,Integer> map=new HashMap<>();
        for (byte b:arr){
            Integer count=map.get(b);
            if(count==null){
                map.put(b,1);
            }else {
                map.put(b,count+1);
            }
        }
        for (Map.Entry<Byte,Integer> entry:map.entrySet()){
            nodes.add(new HCNode(entry.getKey(), entry.getValue()));
        }
        return nodes;
    }

//根据叶子节点创建Huffman树
    public static HCNode createHuffmanTree(List<HCNode> nodes){
        while (nodes.size()>1){
            Collections.sort(nodes);
            HCNode leftNode=nodes.get(0);
            HCNode rightNode=nodes.get(1);
            HCNode parentNode=new HCNode(null, leftNode.weight+rightNode.weight);
            parentNode.left=leftNode;
            parentNode.right=rightNode;
            nodes.remove(leftNode);
            nodes.remove(rightNode);
            nodes.add(parentNode);
        }
        return nodes.get(0);
    }

//根据Huffman树得到Huffman编码表
    public static Map<Byte,String> getCodes(HCNode root) {
        if (root == null) {
            return null;
        } else {
            StringBuilder sb = new StringBuilder();
            getCodes(root.left,"0",sb);
            getCodes(root.right,"1",sb);
            return encodingTable;
        }
    }
    public static void getCodes(HCNode node,String code,StringBuilder sb){
        StringBuilder temp=new StringBuilder(sb);
        temp.append(code);
        if(node!=null){
            if(node.data==null){
                getCodes(node.left,"0",temp);
                getCodes(node.right,"1",temp);
            }else {
                encodingTable.put(node.data,temp.toString());
            }
        }
    }

//arr 要压缩的字节数据
//根据arr得到的Huffman编码表
//压缩数据
public static byte[] zip(byte[] arr,Map<Byte,String> encodingTable){
        StringBuilder sb=new StringBuilder();
        for (byte b:arr){
            sb.append(encodingTable.get(b));
        }
        int len= (sb.length()+7)/8;
        byte[] bytes=new byte[len];
        int count=0;
        for (int i=0;i<sb.length();i+=8){
            String s;
            if(i+8>sb.length()){
                s= sb.substring(i);
                last=s;
            }else {
                s=sb.substring(i,i+8);
            }
            bytes[count++]=(byte)Integer.parseInt(s,2);
        }
        return bytes;
    }

//zipData 压缩后的数据
//用原Huffman编码表对zipData解码
public static byte[] decode(byte[] zipData,Map<Byte,String> encodingTable){
        StringBuilder sb=new StringBuilder();
        for (int i=0;i<zipData.length;i++){
            if(i==zipData.length-1){
                sb.append(last);
                break;
            }
            sb.append(toBin(zipData[i]));
        }
        Map<String,Byte> decodeTable=new HashMap<>();
        for (Map.Entry<Byte,String> entry:encodingTable.entrySet()){
            decodeTable.put(entry.getValue(),entry.getKey());
        }
        List<Byte> list=new ArrayList<>();
        for (int i=0;i<sb.length();){
            int count=1;
            Byte b;
            while (true){
                String s=sb.substring(i,count+i);
                b=decodeTable.get(s);
                if(b==null){
                    count++;
                }else {
                    break;
                }
            }
            i+=count;
            list.add(b);
        }
        byte[] arr=new byte[list.size()];
        for (int i=0;i<list.size();i++){
            arr[i]=list.get(i);
        }
        return arr;
    }

//转二进制
 public static String toBin(byte b){
        int temp=b;
        temp |= 256;
        String s=Integer.toBinaryString(temp);
        return s.substring(s.length()-8);
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值