赫夫曼编码和解码,学习的demo。

package com.source.eight;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class HuffmanCompress {
    private static Map<Byte,String> hufumanMap = new HashMap<Byte,String>(); //存放赫夫曼编码
    private static StringBuilder sb = new StringBuilder(); //拼接路径
    
    public static void main(String[] args) {
        HuffmanCompress hc = new HuffmanCompress();
        String contant = "i like like like java do you like a java absddddd";
        System.out.println("原始数据 " + contant);
        byte[] bys = contant.getBytes();
        //压缩
        byte[] zips = hc.zipMethod(contant.getBytes());
        System.out.println("压缩后 " + Arrays.toString(zips));
        //解压
        String resZip = hc.resZip(zips, bys);
        System.out.println("解压后 " + resZip);
    }
    //封装一个方法用于解码赫夫曼
    public String resZip(byte[] zips,byte[] bys) {
        //返回补码字符串
        String codes = byteToBitString(zips);
        //将赫夫曼字符串解码成String字符串
        String resString = bitStringtoString(codes, bys);
        //返回
        return resString;
    }
    //将赫夫曼字符串解码成String字符串
    private String bitStringtoString(String codes,byte[] bys) {
        //1.将bys数组用list集合保存
        List<CompressNode> nodes = getNodes(bys);
        //2.将nodes集合创建成赫夫曼树
        CompressNode root = createHuffmanTree(nodes);
        //3.使用map集合保存赫夫曼编码
        Map<Byte,String> maps = getCodes(root);
        //4.遍历codes集合
        StringBuilder stringBuilder = new StringBuilder();
        int size = codes.length();
        int buChang = 2;
        Set<Byte> keySet = maps.keySet();
        for (int i = 0; i < size;i += buChang) {
            for (Byte key : keySet) {
                String value = maps.get(key);
                buChang = value.length();
                if (i+buChang <= size) {
                    String res = codes.substring(i, i+buChang);
                    if (res.equals(value)) {
                        byte b = key;
                        stringBuilder.append((char)b);
                        break;
                    }
                }
            }
        }
        return stringBuilder.toString();
    }
    
    
    //解压赫夫曼压缩数组成String字符
    public String byteToBitString(byte[] zips) {
        StringBuilder stringBuilder = new StringBuilder();
        //遍历zips数组
        int len = zips.length;
        for(int i = 0; i < len; i++) {
            if (i+1 == zips.length) {
                String complement = byteToBitComplement(zips[i]);
                int count = 0;
                for(int j = 0; j < complement.length(); j++) {
                    if (complement.charAt(j) != '0') {
                        count = j;
                        break;
                    }
                }
                complement = complement.substring(count);
                stringBuilder.append(complement);
            }else {
                stringBuilder.append(byteToBitComplement(zips[i]));
            }
        }
        return stringBuilder.toString();
    }
    
    /**
     * 
     * @param 将一个字节 转换为对应的补码
     * @return
     */
    private String byteToBitComplement(byte b) {
        String complement = "00000000";
        //1.判断b的正负
        if (b > 0) {
            //补码和原码一致所有直接除2
            StringBuilder sb = new StringBuilder();
            int n = 0;
            while (b > 0) {
                n = b % 2;
                sb.append(n);
                b /= 2;
            }
            
            while (sb.length() < 8) {
                sb.append("0");
            }
            //sb反转
            sb.reverse();
            complement = sb.toString();
        }else if (b < 0){
            b = (byte) Math.abs(b);
            //b小于0,先获取b的原码再获取反码最后获取补码
            //1.获取原码
            StringBuilder sb = new StringBuilder();
            int n = 0;
            while (b > 0) {
                n = b % 2;
                sb.append(n);
                b /= 2;
            }
            
            while (sb.length() < 8) {
                sb.append("0");
            }
            //sb反转
            sb.reverse();
            String yuanMa = sb.toString();
            //通过原码获取反码
            StringBuilder sb1 = new StringBuilder();
            for(int i = 0; i < 8;i++) {
                char c = yuanMa.charAt(i);
                if (c == '1') {
                    sb1.append('0');
                }else {
                    sb1.append('1');
                }
            }
            //通过反码获取补码
            StringBuilder sb2 = new StringBuilder();
            String fanMa = sb1.toString();
            fanMa = fanMa.substring(0, fanMa.length()-1) + (Integer.parseInt(fanMa.substring(fanMa.length()-1)) + 1);
            //循环遍历获取补码
            for (int i = 7 ; i >= 0;i--) {
                if (fanMa.charAt(i) == '2') {
                    sb2.append("0");
                    fanMa = fanMa.substring(0, i-1) + (Integer.parseInt(fanMa.substring(i-1,i)) + 1) + fanMa.substring(i);
                }else {
                    sb2.append(fanMa.charAt(i));
                }
            }
            sb2.reverse();
            complement = sb2.toString();
        }
        return complement;
    }
    
    //封装一个方法,返回赫夫曼压缩数组
    public byte[] zipMethod(byte[] bys) {
        //1.将bys数组用list集合保存
        List<CompressNode> nodes = getNodes(bys);
        //2.将nodes集合创建成赫夫曼树
        CompressNode root = createHuffmanTree(nodes);
        //3.使用map集合保存赫夫曼编码
        Map<Byte,String> maps = getCodes(root);
        //4.返回压缩后的数组
        byte[] zip = zip(bys, maps);
        return zip;
    }
    
    //返回赫夫曼处理的编码
    private static byte[] zip(byte[] bys,Map<Byte,String> hufumanMap) {
        //1.获取赫夫曼编码
        StringBuilder sb = new StringBuilder();
        for (byte b : bys) {
            sb.append(hufumanMap.get(b));
        }
        //2.将编码8个为一位转换为字节
        //确定tempByte【】的大小
        int len;
        if (sb.length() % 8 == 0) {
            len = sb.length() / 8;
        }else {
            len = sb.length() / 8 + 1;
        }
        
        byte[] tempByte = new byte[len];
        String str = "";
        int index = 0;//记录第几个byte
        //for循环遍历sb
        for (int i = 0; i <sb.length(); i += 8) {
            if (i+8 < sb.length()) {
                str = sb.substring(i, i+8);
            }else {
                str = sb.substring(i);
            }
            //(byte)Integer.parseInt(str, 2);
            tempByte[index++] = (byte)Integer.parseInt(str, 2);
        }
        return tempByte;
    }
    
    //生成赫夫曼编码 重载
    private static Map<Byte, String> getCodes(CompressNode node) {
        if (node == null) {
            return null;
        }
        getCodes(node, "", sb);
        return hufumanMap;
    }
    //生成赫夫曼编码
    private static void getCodes(CompressNode node,String code,StringBuilder sb) {
        StringBuilder stringBuilder = new StringBuilder(sb);
        stringBuilder.append(code);
        
        if (node.data == null) {
            //向左遍历
            getCodes(node.left, "0", stringBuilder);
            //向右遍历
            getCodes(node.right, "1", stringBuilder);
        }else {
            //保存叶子节点到map中
            hufumanMap.put(node.data, stringBuilder.toString());
        }
    }
    
    //创建赫夫曼树
    private CompressNode createHuffmanTree(List<CompressNode> nodes) {
        while (nodes.size() > 1) {
            //排序
            Collections.sort(nodes);
            //选择 ndoes 0 1 两个节点
            CompressNode leftNode = nodes.get(0);
            CompressNode rightNode = nodes.get(1);
            //创建新的节点
            CompressNode newNode = new CompressNode(null, leftNode.weight + rightNode.weight);
            newNode.left = leftNode;
            newNode.right = rightNode;
            //将新节点加入nodes中
            nodes.add(newNode);
            //删除左右两个节点
            nodes.remove(leftNode);
            nodes.remove(rightNode);
        }
        return nodes.get(0);
    }
    //将byte[] 转换为list集合
    private List<CompressNode> getNodes(byte[] bytes) {
        //统计bytes数组里的元素
        Map<Byte,Integer> map = new HashMap<Byte,Integer>();
        for (byte b : bytes) {
            //根据key获取值
            Integer res = map.get(b);
            if (res == null) {
                map.put(b, 1);
            }else {
                res += 1;
                map.put(b, res);
            }
        }
        //创建List集合
        List<CompressNode> nodes = new ArrayList<CompressNode>();
        //遍历map集合创建CompressNode节点并添加到nodes集合
        Set<Byte> keySet = map.keySet();
        for (Byte b : keySet) {
            CompressNode compressNode = new CompressNode(b, map.get(b));
            nodes.add(compressNode);
        }
        //测试 输出nodes节点
        //System.out.println(nodes);
        //从小到大排序
        //Collections.sort(nodes);
        //再次输出
        //System.out.println(nodes);
        return nodes;
    }
    
    
}


class CompressNode implements Comparable<CompressNode>{
    public Byte data;
    public Integer weight;
    public CompressNode left;
    public CompressNode right;
    
    public CompressNode(Byte data, Integer weight) {
        this.data = data;
        this.weight = weight;
    }

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

    @Override
    public String toString() {
        return "CompressNode [data=" + data + ", weight=" + weight + "]";
    }
    //前序遍历
    public void preSort() {
        System.out.println(this);
        if(this.left != null) {
            this.left.preSort();
        }
        if(this.right != null) {
            this.right.preSort();
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值