利用哈夫曼树进行文件压缩与解压

package com.example.demo.code50;

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

/**
 * @author ming
 * @create 2022/5/31
 * @description:
 */
public class HuffmanCode {
    private static Map<String,Object> mapGlobal = new HashMap<String,Object>();
    static class Node implements Comparable<Node> {
        Byte data;
        int weight;
        Node left;
        Node right;

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

        }

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

        @Override
        public int compareTo(Node o) {
            return this.weight-o.weight;
        }
    }
    public static Node createHuffmanTree(String Str){
        byte[] array = Str.getBytes();
        List<Node> nodes = new ArrayList<Node>();
        //[node={'a',6},node={'b',9}]
        int len = array.length;
        for (int i = 0; i < len; i++) {
            Node temp = null;
            for (Node node : nodes) {
                if (node.data == array[i]) {
                    temp = node;
                }
            }
            if(temp != null){
                Node node = new Node(temp.data, temp.weight + 1);
                nodes.remove(temp);
                nodes.add(node);
            }else{
                Node node = new Node(array[i], 1);
                nodes.add(node);
            }
        }
        //根据list创建哈夫曼树
        while(nodes.size()>1){
            Collections.sort(nodes);
            Node leftChild = nodes.get(0);
            Node rightChild = nodes.get(1);
            Node pareNode = new Node( null,leftChild.weight + rightChild.weight);
            pareNode.left = leftChild;;
            pareNode.right = rightChild;
            nodes.remove(leftChild);
            nodes.remove(rightChild);
            nodes.add(pareNode);
        }
        return nodes.get(0);
    }
    public static Map<Byte,String> getCode(Node node){
        Map<Byte,String> map = new HashMap<Byte,String>();
        StringBuilder sb = new StringBuilder();
        return createHuffmanCode(map,sb,node);
    }
    public static Map<Byte,String> createHuffmanCode(Map<Byte,String> map,StringBuilder sb,Node node){
        //map<Byte,String>  32-01

        if(node == null) return map ;
        if(node.left!=null){
            sb.append(1);
            createHuffmanCode(map,sb,node.left);
            //回溯会添加上次的字符串编码
            sb.replace(sb.length() - 1, sb.length(), "");
        }

        if(node.right!=null){
             sb.append(0);
             createHuffmanCode(map,sb,node.right);
            sb.replace(sb.length() - 1, sb.length(), "");
        }
        map.put(node.data,sb.toString());
        sb=new StringBuilder();
        return map;

    }
    public static void showPre(Node node){
        if(node==null) return ;
        System.out.println(node);
        showPre(node.left);
        showPre(node.right);
    }
    public static Map<String,Object> zip(String str) throws IOException {
        byte[] bytes = str.getBytes();
        Node node = createHuffmanTree(str);
        Map<Byte, String> huffmanCode = getCode(node);
        StringBuilder sb = new StringBuilder();
        for (byte aByte : bytes) {
            sb.append(huffmanCode.get(aByte));

        }
        //11000000                                              
        //计算发送数组的长度
        System.out.println(sb);
        int len = (sb.length()+7)/8;
        byte[] sendByte  = new byte[len];
        String temp = "";
        int index = 0;
        for (int i = 0; i < len; i++) {
            if(index+8>sb.length()){
                temp = sb.substring(index);
            }else{
                temp = sb.substring(index,index+8);
            }

            sendByte[i] = (byte) Integer.parseInt(temp,2);
            index = index + 8;
        }
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File("D:\\Desktop\\ming.zip")));
        HashMap<String,Object> tempMap = new HashMap<String,Object>();
        try {
            out.write(sendByte,0,sendByte.length);
            tempMap.put("byteArray",sendByte);
            tempMap.put("len",sb.length());
            tempMap.put("code",huffmanCode);
            return tempMap;
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
             out.close();
             return tempMap;
        }

    }
    public static String toBinary(byte num,boolean flag) {
        int n = num;
        if(flag){
            n =  n|256;

        }
        String s = Integer.toBinaryString(n);

        if(flag){
            return s.substring(s.length()-8);
        }else{
            return s;
        }
    }
    public static void unZip(Map<Byte,String> map,byte[] bytes,int len){
        int last = 0;
        StringBuilder sb = new StringBuilder();
        boolean flag = true;
        for (int i = 0; i < bytes.length; i++) {
            if(i==bytes.length-1) {
                StringBuilder builderString = new StringBuilder();
                flag = false;
                last = len-sb.length();
                String s = toBinary(bytes[i], flag);
                last = last - s.length();
                while(last>0){
                    builderString.append("0");
                    last--;
                }
                builderString.append(s);
                sb.append(builderString.toString());
            }else{
                String s = toBinary(bytes[i], flag);
                sb.append(s);
            }

        }
        System.out.println(sb);
        //32-10 反转 10-32
        Map<String,Byte> reverseHuffman = new HashMap<String,Byte>();
        for (Byte aByte : map.keySet()) {
           String value =  map.get(aByte);
           reverseHuffman.put(value,aByte);
        }
        List<Byte> list = new ArrayList<Byte>();
        String tempStr = "";
        for (int i = 0; i < sb.length(); i++) {
             tempStr =tempStr + sb.charAt(i)    +"";
             if(reverseHuffman.containsKey(tempStr)){
                 list.add(reverseHuffman.get(tempStr));
                 tempStr = "";
             }
        }
        byte[] byteArray = new byte[list.size()];
        for (int i = 0; i < list.size(); i++) {
            byteArray[i] = list.get(i);
        }
        BufferedOutputStream out = null;
        try {
            out  = new BufferedOutputStream(new FileOutputStream(new File("D:\\Desktop\\ming2.txt")));
            out.write(byteArray,0,byteArray.length);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    //文件压缩
    public static void  zipFile(){
        BufferedReader reader = null;
        String str ="";
        try {
            File file = new File("D:\\Desktop\\ming.txt");
             reader = new BufferedReader(new FileReader(file));
            str  = str +  reader.readLine();
            mapGlobal = zip(str);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public static void unZipFile(){
         byte[] byteArray = (byte[]) mapGlobal.get("byteArray");
         int len = (int) mapGlobal.get("len");
         Map<Byte,String> huffmanCode = (Map<Byte, String>) mapGlobal.get("code");
         unZip(huffmanCode, byteArray, len);
    }
    public static void main(String[] args) throws IOException {
       zipFile();
       unZipFile();
    }
}

综合实验: 1. 问题描述 利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。这要求在发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站编写一个哈夫曼码的编/译码系统。 2. 基本要求 一个完整的系统应具有以下功能: (1) I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。 (2) E:编码(Encoding)。利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。 (3) D:译码(Decoding)。利用已建好的哈夫曼树文件CodeFile中的代码进行译码,结果存入文件Textfile中。 (4) P:印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。 (5) T:印哈夫曼树(Tree printing)。将已在内存中的哈夫曼树以直观的方式(比如树)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint 中。 3. 测试数据 用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FAVORITE”。 字符 A B C D E F G H I J K L M 频度 186 64 13 22 32 103 21 15 47 57 1 5 32 20 字符 N O P Q R S T U V W X Y Z 频度 57 63 15 1 48 51 80 23 8 18 1 16 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值