huffman编码Java实现

实现思路

huffmantree的创建、压缩和解压

创建思路
1、写一个方法得到对应的String的Byte数组
2、创建一个Node节点:
属性:data(每个数据的asc码) weight(数据出现的次数) left right
继承Comparable
方法:toString(重写toString) preOrder(前序遍历) comparableto(比较大小的方法)
3、方法:将Byte数组转化为map集合(key存储数据,value存储出现的次数)
4、将map集合转化为list
5、对list进行节点的huffmantree排序,使之只有一个节点
代码

package com.atguigu.huffmanCode;


import java.io.*;
import java.util.*;

/**
 * huffmantree的创建、压缩和解压
 *
 *
 * 创建思路
 *  1、写一个方法得到对应的String的Byte数组
 *  2、创建一个Node节点:
 *      属性:data(每个数据的asc码) weight(数据出现的次数) left  right
 *      继承Comparable
 *      方法:toString(重写toString) preOrder(前序遍历) comparableto(比较大小的方法)
 *  3、方法:将Byte数组转化为map集合(key存储数据,value存储出现的次数)
 *  4、将map集合转化为list
 *  5、对list进行节点的huffmantree排序,使之只有一个节点
 */
public class Huffmancode {
    static StringBuilder Strbul = new StringBuilder();
    static Map<Byte,String> codes = new HashMap<Byte,String>();
    public static void main(String[] args) {
        //测试文件的压缩,外部文件
        String inFile = "D:\\www.bmp";
        String outFile = "D:\\qqq.zip";
        zip(inFile,outFile);
        System.out.println("压缩成功");
       //解压文件
        String zipFile = "D:\\qqq.zip";
        String dstFile = "D:\\www2.bmp";
        unZip(zipFile,dstFile);
        System.out.println("解压成功");
       /* java.lang.String datas = "i like like like java do you like a java";
        byte[] overcodes = huffmanTreeBytes(datas);
        System.out.println("经过压缩后结果为" + Arrays.toString(overcodes) + "\n长度为" + overcodes.length);

        //解码
        byte[] overbytes = decode(getCodes(datas),overcodes);
        System.out.println("解码后的结果为" + new String(overbytes));
*/
//        codesToString(huffmanTreeBytes(datas));//查看解码后的二进制编码101010111100111.这种形式
        /*
//        byte[] bytesDatas = StringTobyte(datas);
//        System.out.println("初始的数据长度为" + bytesDatas.length);
        //将字符串转化为链表形式的数据
        List<Node> nodes = byteToMap(StringTobyte(datas));
//        System.out.println(nodes);
        //将哈夫曼树生成
        Node root = createHuffmanTree(nodes);
        System.out.println("root为" );
        //前序遍历哈夫曼树
        root.preOrder();
        //生成的hufuman编码表为
        System.out.println("huffman编码表为");
        Map<Byte,String> codes = createcodes(root);
        System.out.println(codes);*/


    }

    /**
     * 用于解压文件
     * @param zip
     * @param dstFile
     */
    public static void unZip(String zip,String dstFile){
        //创建输入流
        InputStream is = null;
        //定义一个对象输入流
        ObjectInputStream ois = null;
        //定义一个文件的输出流
        OutputStream os = null;
        try {
            //创建文件输入流
            is = new FileInputStream(zip);
            //创建一个和is关联的文件输入流
            ois = new ObjectInputStream(is);
            //读取Byte数组
            byte[] bytes = (byte[]) ois.readObject();
//            System.out.println("待解码的Byte数组为" + new String(bytes));
            //读取霍夫曼编码表
            Map<Byte,String> codes = (Map<Byte, String>) ois.readObject();
            System.out.println("解码的map为" + codes);
            //解码
            byte[] overcode = new byte[2];//decode(codes,bytes);
            //将bytes写入到目标文件
            os = new FileOutputStream(dstFile);
            os.write(overcode);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                os.close();
                ois.close();
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }

   /* *
     * 用于解压文件
     * @param zipFile 待解压的文件
     * @param dstFile  解压完放入的路径
     */
    public static void unZip2(String zipFile,String dstFile){
        //创建输入流、输出流、输入流对象
        InputStream is = null;
        ObjectInputStream ois = null;
        OutputStream os = null;
        try {
            //创建输入流
            is = new FileInputStream(zipFile);
            ois = new ObjectInputStream(is);
            //读取被编码后的数组
            byte[] bytes = (byte[]) ois.readObject();
            //获取霍夫曼编码
            Map<Byte,String> huffmanTreeCodes = (Map<Byte, String>) ois.readObject();
            //解码
            byte[] overbytes = new byte[2];//decode(huffmanTreeCodes,bytes);
            //创建输出对象
            os = new FileOutputStream(dstFile);
            //输出到文件
            os.write(overbytes);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                os.close();
            } catch (IOException e) {
                System.out.println("关闭os错误");
                e.printStackTrace();
            }
            try {
                ois.close();
            } catch (IOException e) {
                System.out.println("关闭ois错误");
                e.printStackTrace();
            }
            try {
                is.close();
            } catch (IOException e) {
                System.out.println("关闭is错误");
                e.printStackTrace();
            }

        }
    }
    /**
     * 用以压缩文件的方法
     * @param srcFile 等待压缩的文件路径
     * @param dstFile  压缩完毕输出的路径
     */
    public static void zip(String srcFile,String dstFile){
        //创建输入流、输出流
        FileInputStream is = null;
        FileOutputStream os = null;
        ObjectOutputStream oos = null;
        try {
            //创建输入流
            is = new FileInputStream(srcFile);
            //创建临时存储的数组
            byte[] bytes = new byte[is.available()];
            //将文件写入到临时数组中
            is.read(bytes);
            //压缩
            byte[] overfile = huffmanTreeBytes(bytes);
            //写入到输出流
            os = new FileOutputStream(dstFile);
//            os.write(overfile);
            //将霍夫曼编码写入到输出流
            oos = new ObjectOutputStream(os);
            oos.writeObject(overfile);
            oos.writeObject(getCodes(bytes));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
                os.close();
                oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
    /**
     * 将byte数组解码的方法
     * @param huffmantree  霍夫曼编码
     * @param codes  待解码的数组
     * @return  返回的结果
     */
    public static byte[] decode(Map<Byte,String> huffmantree , byte[] codes){
        //用于解码的map
        Map<String,Byte> decodeMap = new HashMap<String,Byte>();
        for (Map.Entry<Byte,String> entry:huffmantree.entrySet()) {
            decodeMap.put(entry.getValue(),entry.getKey());
        }
//        System.out.println("反编码的集合为" + decodeMap);\
        //overCodes 解码后的二进制数据0101101010
        String overCodes = codesToString(codes);
        List<Byte> decode = new ArrayList<>();//结果
        for (int i = 0; i < overCodes.length(); ) {
            boolean flag = true;//临时变量
            int count = 1;
            Byte b = null;
            while(flag){
                String key = overCodes.substring(i,i + count);
                b = decodeMap.get(key);
                if (b == null){
                    count++;
                }else {
                    flag = false;
                }
            }
            decode.add(b);
            i += count;
        }
        byte[] overbytes = new byte[decode.size()];
        for (int i = 0; i < decode.size(); i++) {
            overbytes[i] = decode.get(i);
        }
//        System.out.println("解码后的结果为" + new String(overbytes));
        return overbytes;
    }

    /**
     * 将压缩后的byte数组转化为字符串
     * @param codes  byte数组
     * @return  返回字符串
     */
    public static String codesToString(byte[] codes){
        StringBuilder str = new StringBuilder();
        for (int i = 0; i < codes.length; i++) {
            if ( i == codes.length - 1){
               str.append(byteToBitString(false,codes[i]));
            }else{
                str.append(byteToBitString(true,codes[i]));
            }
        }
//        System.out.println("解码后的二进制数据为为" + str.toString());
        return str.toString();
    }
    /**
     * 将byte转化为字符串,即转化为100101010...的形式
     * @param b  传入的数据
     * @param flag  当为正数或者最后一位
     * @return  返回一个字符串
     */
    public static String byteToBitString(boolean flag,byte b){
        int temp = b;
        if (flag){
            temp |= 256;
        }
        String str = Integer.toBinaryString(temp);
        if (flag){
            return str.substring(str.length() - 8 );
        }else{
            return str;
        }
    }
    public static byte[] huffmanTreeBytes(byte[] bytes){
        int overByteLen = 0;
        //用来拼接临时编码值的
        StringBuilder strbul = new StringBuilder();
        //获得编码
        Map<Byte,String> codes = getCodes(bytes);
        //将数组中的所有值对应的哈夫曼编码拼接
        for (byte value: bytes) {
            strbul.append(codes.get(value));
        }
        //创建结果的Byte数组
        byte[] overBytes = new byte[(strbul.length() + 7) / 8 ];
        int index = 0;
        //将编码转换为二进制的数据
        for (int i = 0; i < strbul.length(); i = i + 8) {
            String momentstr;
            if ((i + 8) > strbul.length()){
                momentstr = strbul.substring(i);
            }else{
                momentstr = strbul.substring(i,i + 8);
            }
//            overBytes[index++] = Byte.parseByte(momentstr,2);  不可以这样写,会越界
            overBytes[index++] = (byte) Integer.parseInt(momentstr,2);
        }
        return overBytes;

    }
    //将String字符串按照编码规则转化为编码
    public static byte[] huffmanTreeBytes(String str){
        int overByteLen = 0;
        //用来拼接临时编码值的
        StringBuilder strbul = new StringBuilder();
        //bytes 表示将String每一个字符转化为了数组中的值
        byte[] bytes = StringTobyte(str);
        //获得编码
        Map<Byte,String> codes = getCodes(str);
        //将数组中的所有值对应的哈夫曼编码拼接
        for (byte value: bytes) {
            strbul.append(codes.get(value));
        }
        //创建结果的Byte数组
        byte[] overBytes = new byte[(strbul.length() + 7) / 8 ];
        int index = 0;
        //将编码转换为二进制的数据
        for (int i = 0; i < strbul.length(); i = i + 8) {
            String momentstr;
            if ((i + 8) > strbul.length()){
                momentstr = strbul.substring(i);
            }else{
                momentstr = strbul.substring(i,i + 8);
            }
//            overBytes[index++] = Byte.parseByte(momentstr,2);  不可以这样写,会越界
            overBytes[index++] = (byte) Integer.parseInt(momentstr,2);
        }
        return overBytes;

    }

    /**
     * 获得编码的方法
     * @param str  传入的字符串
     * @return  为传入字符串对应的哈希编码
     */
    public static Map<Byte,String> getCodes(String str){
        //bytes 表示将String每一个字符转化为了数组中的值
        byte[] bytes = StringTobyte(str);
        //将字符串数组转化为链表
        List<Node> nodes = byteToMap(bytes);
        //创建哈希曼树
        Node root = createHuffmanTree(nodes);
        return createcodes(root);
    }
    /**
     * 获得编码的方法
     * @param bytes  传入的数组
     * @return  为传入字符串对应的霍夫曼编码
     */
    public static Map<Byte,String> getCodes(byte[] bytes){
        //将字符串数组转化为链表
        List<Node> nodes = byteToMap(bytes);
        //创建哈希曼树
        Node root = createHuffmanTree(nodes);
        return createcodes(root);
    }

    //获得哈夫曼编码
    public static Map<Byte,String> createcodes(Node root){
        if (root != null){
            return createcodes(root,"",Strbul);
        }else {
            return null;
        }
    }
    public static Map<Byte,String> createcodes(Node root,String code,StringBuilder Strbul){
        StringBuilder StrBul2 = new StringBuilder(Strbul);
        StrBul2.append(code);
        if (root != null){
            if (root.data == null){
                createcodes(root.left,"0",StrBul2);
                createcodes(root.right,"1",StrBul2);
            }else {
                codes.put(root.data,StrBul2.toString());
            }
        }
        return codes;
    }
    //创建赫夫曼树
    public static Node createHuffmanTree(List<Node> nodes){
        while(nodes.size() >1){
            //1、排序
            Collections.sort(nodes);
            //2、取出两个最小的
            Node leftNode = nodes.get(0);
            Node rightNode = nodes.get(1);
            //3、创建新节点
            Node parent = new Node(null,leftNode.weight + rightNode.weight);
            parent.left = leftNode;
            parent.right = rightNode;
            //4、删除节点
            nodes.remove(leftNode);
            nodes.remove(rightNode);
            //5、添加节点
            nodes.add(parent);
        }
        return nodes.get(0);
    }
    //将String转化为byte 数组
    public static byte[] StringTobyte(String str){
        return str.getBytes();
    }
    //将byte数组转化为集合
    public static List<Node> byteToMap(byte[] bytes){

        List<Node> nodes = new ArrayList<Node>();
        Map<Byte,Integer> count = new HashMap<>();
        for (int i = 0; i < bytes.length; i++) {
            Integer times = count.get(bytes[i]);
            if (count.get(bytes[i]) == null) {
                count.put(bytes[i], 1);
            } else {
                count.put(bytes[i], times + 1);
            }

        }
        for (Map.Entry<Byte,Integer> entry:count.entrySet()) {
            nodes.add(new Node(entry.getKey(),entry.getValue()));
        }
        return nodes;
    }
    //节点的前序遍历
    public static void perOrder(Node root){
        if (root != null){
            root.preOrder();
        }else{
            System.out.println("树为空");
        }
    }
}

/**
 *
 */
class Node implements Comparable<Node>{
    Byte data;
    int weight;
    Node left;
    Node right;


    public void preOrder(){
        System.out.println(this);
        if (this.left != null){
            this.left.preOrder();
        }
        if (this.right != null){
            this.right.preOrder();
        }
    }
    @Override
    public int compareTo(Node o) {
        return this.weight - o.weight;
    }

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

    public Node(Byte data, int weight) {
        this.data = data;
        this.weight = weight;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值