winRAR真难用,我决定自创一个(筑基期)适合无基础

筑基期简介

筑基期主要阐述的是对于压缩和解压所需要的原理,主要是文字描述与少量图片分析 

提供完整代码,可不学习直接使用      博主空间https://blog.csdn.net/JOElib?spm=1011.2266.3001.5343强哥的查找算法https://blog.csdn.net/JOElib/article/details/123848806?spm=1001.2014.3001.5501

定义概述 

路径

路径

        路径是从根节点如何走到目标节点,中间的过程被称为路径

 

路径的长度

        路径的长度是在走的过程中,中间经历的节点数,如第L层的节点的路径长度是L-1

节点的权

        节点的权是节点中被赋予了某个特殊意义的数字,该数字被称为节点的权

带权路径长度

        用节点的路径大小乘上节点的权,乘积被称为带权路径

树的带权路径长度

        树的带权路径表示所有叶子节点的带权路径之和,和被称为树的带权路径,树的带权路径的简写是WPL

哈夫曼树

        哈夫曼树是一种特殊的二叉树,这种二叉树的WPL最小,即树的带权路径最小的二叉树就被称为哈夫曼树,其特点是越大的权离节点越近。

存储方式

定长编码

        以字符串为例,按照每一个字符的ASCII码对应的二进制补码,原封不动的存储,被我们称为定长编码

变长编码

        以字符串为例,先统计里面每一个字符出现的元素个数,先将他们排序,按照排序顺序,给较大的ASCII编一个较小的二进制编码,利用这些编码去存储

        缺点:该编码读取会产生歧异,如01 与011编码,他们两个前缀相同,读取的是一个一个去读的,假设我们想要的是011,系统可能读成了01

前缀编码

        前缀编码,即每一个变长编码的前缀都不一样,可避免上述读取产生歧异的缺点

哈夫曼编码

        哈夫曼编码是一种特殊的前缀编码,根据路径从而得到对应的哈夫曼编码


完整代码 

package datastructure.chapter04.tree.huffman.huffmancoding;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 江骏杰
 * Date: 2022-03-29
 * Time: 21:38
 */
public class Node implements Comparable<Node> {
    public Byte ascii;
    public int value;
    public Node left;
    public Node right;

    public Node(Byte ascii,int value) {
        this.ascii = ascii;
        this.value = value;
    }

    public String toString() {
        return "Node[ascii = " + ascii + " value = " + value + "]";
    }

    public int compareTo(Node node) {
        return value - node.value;
    }

}
package datastructure.chapter04.tree.huffman.huffmancoding;

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 江骏杰
 * Date: 2022-03-29
 * Time: 21:37
 */
public class HuffmanCode implements Serializable {

    @Serial
    private static final long serialVersionUID = 4420;
    private static final HashMap<Byte,String> HUFFMAN_CODES = new HashMap<>();
    private static final StringBuffer STRING_BUFFER = new StringBuffer();
    private static int lastCount;

    public static byte[] huffmanCodeZip(String s) {
        var content = s.getBytes();
        var list = getNodes(content);
        var huffmanTreeRoot = createHuffmanTree(list);
        getCodes(huffmanTreeRoot,"",STRING_BUFFER);
        return zip(content,HUFFMAN_CODES);
    }

        public static byte[] huffmanCodeZip(byte[] content) {
        var list = getNodes(content);
        var huffmanTreeRoot = createHuffmanTree(list);
        getCodes(huffmanTreeRoot,"",STRING_BUFFER);
        return zip(content,HUFFMAN_CODES);
    }

    public static List<Node> getNodes(byte[] content) {
        var map = new HashMap<Byte,Integer>();
        var list = new ArrayList<Node>();
        for (var item : content) {
            var count = map.get(item);
            if (count == null) {
                map.put(item,1);
            }else {
                map.put(item,++count);
            }
        }
        for (var entry : map.entrySet()) {
            list.add(new Node(entry.getKey(),entry.getValue()));
        }
        return list;
    }

    public static Node createHuffmanTree(List<Node> list) {
        while (list.size() > 1) {
            Collections.sort(list);
            var leftNode = list.get(0);
            var rightNode = list.get(1);
            var parentNode = new Node(null, leftNode.value + rightNode.value);
            parentNode.left = leftNode;
            parentNode.right = rightNode;
            list.add(parentNode);
            list.remove(1);
            list.remove(0);
        }
        return list.get(0);
    }

    public static void getCodes(Node node,String code,StringBuffer strBuf) {
        var curStrBuf = new StringBuffer(strBuf);
        curStrBuf.append(code);
        if (node != null) {
            if (node.ascii == null) {
                getCodes(node.left,"0",curStrBuf);
                getCodes(node.right,"1",curStrBuf);
            }else {
                HUFFMAN_CODES.put(node.ascii,curStrBuf.toString());
            }
        }
    }

    public static byte[] zip(byte[] content,Map<Byte,String> huffmanCodes) {
        var strBuf = new StringBuilder();
        for (var item : content) {
            strBuf.append(huffmanCodes.get(item));
        }
        var len = (strBuf.length() + 7) / 8;
        var huffmanCodesBytes = new byte[len];
        String str;
        var index = 0;
        for (int i = 0; i < strBuf.length(); i+= 8) {
            if (i + 8 < strBuf.length()) {
                str = strBuf.substring(i,i+8);
            }else {
                str = strBuf.substring(i);
                lastCount = str.length();
            }
            huffmanCodesBytes[index++] = (byte) Integer.parseInt(str,2);
        }
        return huffmanCodesBytes;
    }

    public static String byteToString(byte b,boolean flag) {
        int temp = b;
        temp |= 256;
        String str = Integer.toBinaryString(temp);
        if (flag) {
            return str.substring(str.length() - 8);
        }
        return str.substring(str.length() - lastCount);
    }

    public static byte[] decode(byte[] huffmanCodesBytes,Map<Byte,String> huffmanCodes) {
        var strBil = new StringBuilder();
        for (int i = 0; i < huffmanCodesBytes.length; i++) {
            boolean flag = (i != huffmanCodesBytes.length -1);
            strBil.append(byteToString(huffmanCodesBytes[i],flag));
        }
        var map = new HashMap<String,Byte>();
        for (var entry : huffmanCodes.entrySet()) {
            map.put(entry.getValue(),entry.getKey());
        }
        var list = new ArrayList<Byte>();
        for (int i = 0; i < strBil.length();) {
            Byte b ;
            var count = 1;
            while ((b = map.get(strBil.substring(i, i + count))) == null) {
                count++;
            }
            list.add(b);
            i += count;
        }
        var content = new byte[list.size()];
        for (int i = 0; i < content.length; i++) {
            content[i] =list.get(i);
        }
        return content;
    }

    public static String decode(byte[] huffmanBytes) {
        return new String(decode(huffmanBytes,HUFFMAN_CODES));
    }

    public static void fileZip(String srcPath,String desPath) {
        try(var fis = new FileInputStream(srcPath);
            var fos = new FileOutputStream(desPath);
            var oos = new ObjectOutputStream(fos)
        ) {
            var content = new byte[fis.available()];
            fis.read(content);
            byte[] huffmanBytes = huffmanCodeZip(content);
            oos.writeObject(huffmanBytes);
            oos.writeObject(HUFFMAN_CODES);
            oos.writeObject(lastCount);
            oos.flush();
            fos.flush();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void fileDeZip(String zipPath,String desPath) {
        try(var fis = new FileInputStream(zipPath);
            var ois = new ObjectInputStream(fis);
            var fos = new FileOutputStream(desPath)
        ) {
            var huffmanBytes = (byte[])ois.readObject();
            var huffmanCodes = (Map<Byte,String >)ois.readObject();
            lastCount = (int)ois.readObject();
            var content = decode(huffmanBytes,huffmanCodes);
            fos.write(content);
            fos.flush();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

}

结论 

        欲要完成一个代码,必先了解他的原理,通过这次原理,我们可以窥探一二 

        下篇,我们会开始创建哈夫曼树

猜你喜欢

转载自blog.csdn.net/JOElib/article/details/123892758
今日推荐