哈夫曼树完成字符串的压缩和解压

 

1、实现的压缩工具类

package com.cn.test.tree.zip;


import java.util.*;

/**
 * 压缩工具类
 */
public class ZipUtil {

    public static Map<Integer,String> huffCodes = new HashMap<>();
    public static Map<String,Integer> reverseHuffCodes = new HashMap<>();
    /**
     * 普通字符串压缩
     * @param source
     * @return
     */
    public static byte[] zipString(String source){
        if(source==null){
            return null;
        }
        System.out.println("原始字符串:"+source);
        //构建哈夫曼树列表
        byte[] bytes = source.getBytes();
        System.out.println("原始字节长度:"+bytes.length);

        //构建哈夫曼村
        HuffTree huffTree = new HuffTree();
        huffTree.buildTree(bytes);

        huffTree.obtainHuffCodes(huffTree.getRoot(),"",huffCodes);
        //生成压缩后的字符串二进制数
        StringBuilder binaryBuilder = new StringBuilder();
        for (byte b:bytes){
            binaryBuilder.append(huffCodes.get((int)b));
        }
        String strBinary= binaryBuilder.toString();
        System.out.println("字符串二进制数:"+strBinary);
        //把字符二进制数转换成真实的二进制数
        int len = (strBinary.length()+7)/8;
        byte[] result = new byte[len+1];
        //byte[0]留出来,如果结尾补了位,把补位的数字放在这里
        int index = 1;
        for (int i = 0 ;i <strBinary.length();){
            if(i+8>=strBinary.length()){
                String last = strBinary.substring(i);
                //补位,使其正好是8位
                last += "00000000".substring(8-(i+8-strBinary.length()));
                result[index++] = (byte)Integer.parseInt(last,2);
                result[0] = (byte)(i+8-strBinary.length());
                break;
            }else{
                result[index++] = (byte)Integer.parseInt(strBinary.substring(i,i+8),2);
                i+=8;
            }
        }
        return result;
    }

    /**
     * 将二进制,转换成字符串二进制
     * @param b
     * @return
     */
    public static String byte2Str(byte b){
        String s = Integer.toBinaryString(b);
        if(s.length()>8){
            s = s.substring(s.length()-8);
        }
        if(s.length()<8){
            s = String.format("%08d", Integer.parseInt(s));
        }
        return s;
    }
    /**
     * 解压字符串
     * @param zipBytes
     * @return
     */
    public static String unZip(byte[] zipBytes){
        //解压之后的字符串
        StringBuilder unZipBinaryBuilder = new StringBuilder();
        for (int i = 1 ;i<zipBytes.length;i++){
            byte b = zipBytes[i];
            unZipBinaryBuilder.append(byte2Str(b));
        }
        String unZipBinary = unZipBinaryBuilder.toString();
        //如果有补位,把末尾的补位去掉
        int buWei = zipBytes[0];
        if(buWei>0){
            unZipBinary = unZipBinary.substring(0,unZipBinary.length()-buWei);
        }
        System.out.println("解压之后的字符串二进制数:"+unZipBinary);

        for (Map.Entry<Integer,String > entry:huffCodes.entrySet()){
            reverseHuffCodes.put(entry.getValue(),entry.getKey());
        }
        List<Byte> source = new ArrayList<>();

        int j = 0;
        for (int i = 0 ; j<unZipBinary.length();){
            for (j = i+1 ;j<=unZipBinary.length();j++){
                if(reverseHuffCodes.get(unZipBinary.substring(i,j))!=null){
                    source.add((byte)(int)reverseHuffCodes.get(unZipBinary.substring(i,j)));
                    i = j;
                    break;
                }
            }
        }
        byte[] b = new byte[source.size()];
        int a = 0;
        for(Byte by:source){
            b[a++]=by;
        }
        return new String(b);
    }

    public static void main(String[] args) {
        String source = "Notice on Registration for Internationa Dear international students, According to the scho";
        byte[] bytes = ZipUtil.zipString(source);
        System.out.println("压缩后的字节长度:"+bytes.length);
        System.out.println("解压之后的字符串:"+ZipUtil.unZip(bytes));
    }
}

执行这个工具的结果是:

原始字符串:Notice on Registration for Internationa Dear international students, According to the scho
原始字节长度:90
字符串二进制数:000110001100110111101110001100101001100011111001111101101111101001011101010011010010100110000100011011011000011010100110010110101010100110100101010100110000011100101010110111101010100110010110101010100110100101010100001000111111010011100011100111000101001111000010101100000011101111010011011111001110101011111001110000101110011111111000111111011101111111001
压缩后的字节长度:46
解压之后的字符串二进制数:000110001100110111101110001100101001100011111001111101101111101001011101010011010010100110000100011011011000011010100110010110101010100110100101010100110000011100101010110111101010100110010110101010100110100101010100001000111111010011100011100111000101001111000010101100000011101111010011011111001110101011111001110000101110011111111000111111011101111111001
解压之后的字符串:Notice on Registration for Internationa Dear international students, According to the scho

 

通过这个结果可以看来把字符串从90个字节的长度,压缩到了46个字节,也能够正常解压

 

2、定义的树的节点

package com.cn.test.tree.zip;

/**
 * hufftree的树节点
 */
public class HuffTreeNode implements Comparable<HuffTreeNode>{
    //字符值
    private Integer value;
    //出现的次数
    private Integer weight;
    //左节点
    private HuffTreeNode leftNode;
    //右节点
    private HuffTreeNode rightNode;

    public HuffTreeNode(Integer value, Integer weight) {
        this.value = value;
        this.weight = weight;
    }
    public HuffTreeNode(Integer value, Integer weight,Integer weight2) {
        this.value = value;
        if(weight==null){
            weight = 0;
        }
        if(weight2 == null){
            weight2 = 0;
        }
        this.weight = weight+weight2;
    }

    public Integer getValue() {
        return value;
    }

    public void setValue(Integer value) {
        this.value = value;
    }

    public Integer getWeight() {
        return weight;
    }

    public void setWeight(Integer weight) {
        this.weight = weight;
    }

    public HuffTreeNode getLeftNode() {
        return leftNode;
    }

    public void setLeftNode(HuffTreeNode leftNode) {
        this.leftNode = leftNode;
    }

    public HuffTreeNode getRightNode() {
        return rightNode;
    }

    public void setRightNode(HuffTreeNode rightNode) {
        this.rightNode = rightNode;
    }

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

    @Override
    public int compareTo(HuffTreeNode o) {
        return this.weight - o.weight;
    }
}

3、定义的树

package com.cn.test.tree.zip;

import java.util.*;

/**
 * 哈夫曼树
 */
public class HuffTree {

    private HuffTreeNode root;

    /**
     * 哈夫曼树的具体构建
     * @param nodes
     * @return
     */
    private HuffTreeNode HalfManTree(List<HuffTreeNode> nodes){
        if(nodes == null){
            return null;
        }

        while (nodes.size()>1){
            Collections.sort(nodes);
            HuffTreeNode leftNode = nodes.get(0);
            HuffTreeNode rightNode = nodes.get(1);
            HuffTreeNode parentNode = new HuffTreeNode(null,leftNode.getWeight(),rightNode.getWeight());
            parentNode.setLeftNode(leftNode);
            parentNode.setRightNode(rightNode);
            nodes.remove(0);
            nodes.remove(0);
            nodes.add(parentNode);
        }
        return nodes.get(0);
    }

    /**
     * 获取每一个元素的路径编码
     * 向左是0,右是1
     * @param huffTreeNode
     */
    public void obtainHuffCodes(HuffTreeNode huffTreeNode, String route, Map<Integer,String> huffCodes){
        if(huffTreeNode == null){
            return;
        }

        if(huffTreeNode.getRightNode() == null && huffTreeNode.getLeftNode() == null){
            huffCodes.put(huffTreeNode.getValue(),route);
        }

        if(huffTreeNode.getLeftNode()!=null){
            obtainHuffCodes(huffTreeNode.getLeftNode(),route+"0",huffCodes);
        }
        if(huffTreeNode.getRightNode()!=null){
            obtainHuffCodes(huffTreeNode.getRightNode(),route+"1",huffCodes);
        }
    }

    public HuffTreeNode getRoot() {
        return root;
    }

    public void setRoot(HuffTreeNode root) {
        this.root = root;
    }

    /**
     * 构建哈夫曼树
     * @param bytes
     */
    public void buildTree(byte[] bytes) {
        //TODO 初始化大小待定,后续可以优化
        Map<Integer,Integer> weightMap = new HashMap<>();
        for (byte b:bytes){
            int key = (int)b;
            if(weightMap.get(key) == null){
                weightMap.put(key,1);
            }else{
                weightMap.put(key,weightMap.get(key)+1);
            }
        }
        List<HuffTreeNode> nodeList = new ArrayList<>(weightMap.size());
        for (Map.Entry<Integer,Integer> entry :weightMap.entrySet()){
            nodeList.add(new HuffTreeNode(entry.getKey(),entry.getValue()));
        }
        this.setRoot(HalfManTree(nodeList));
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值