• 哈夫曼编码


    离开了校园,连手机流量都要省着用,然后突发奇想的思考如何才能节省传输大小



    1. 哈夫曼树

    构建最短带权路径长度的二叉树,叫做哈夫曼树,也叫最优树(权重越大的结点离树根越近)


    1.1 基本定义

    • 路径:树中的一个节点到另一个节点之间的通路
    • 路径长度:某路径中所经过的节点数量
    • 节点的权:给节点赋值,这个值称为节点的权
    • 节点的带权路径长度:根节点到某节点的路径长度 * 该节点的权
    • 树的带权路径长度:树中所有叶子节点的带权路径长度之和,记作 "WPL"


    1.2 构建步骤

    • 选出两个最小权值作为左右子树,新建其父节点(虚线),权值为左右子树权值之和
    • 从权值队列中删除第一步的左右子树的权值,添加第一步新增的二叉树到权值队列
    • 重复第一、二步,直到构建完权值队列中所有节点


    1.3 构建图示

    WPL:9 * 1 + 6 * 2 + 4 * 3 + 1 * 3 = 36





    2. 哈夫曼编码

    哈夫曼编码是一种编码方式,其可以对信息进行压缩,而从提高存储,传输的效率


    2.1 基本定义

    • 等长编码:任何字符的编码长度都相同,比如ASCII。虽读写方便,但浪费资源,且有前缀码问题
    • 无前缀编码:任一个编码都不是其他任何编码的前缀。[01,10,11,100,101]中10是100的前缀,因此不是无前缀编码


    2.2 构建步骤

    • 根据权值构建哈夫曼树
    • 将哈夫曼树的左树标 0,右树标记1,根节点不计算
    • 将权值替换为对应的字符
    • 列出字符对应的二进制


    2.3 构建图示

    假设字符A、B、C、D对应的权值为1、9、4、6

    (4)

    字符 编码
    A 000
    B 1
    C 001
    D 01


    2.4 哈夫曼编码应用

    通过哈夫曼编码传输文本、图片,查看前后对比


    2.4.1 哈夫曼编码 java 实现

    /**
     * @author Howl
     * 哈夫曼编码
     */
    public class HuffmanCode {
        /**
         * 哈夫曼树结点结构
         */
        private static class Node implements Comparable<Node> {
            /**
             * 权值、二进制编码0、1、左右孩子
             */
            int weight;
            String code;
            Node left;
            Node right;
    
            Node(int weight) {
                this.weight = weight;
            }
    
            Node(int weight, Node left, Node right) {
                this.weight = weight;
                this.left = left;
                this.right = right;
            }
    
            @Override
            public int compareTo(Node o) {
                return Integer.compare(this.weight, o.weight);
            }
        }
    
        /**
         * 根节点、存储全部节点
         */
        private Node root;
        private static Node[] nodes;
    
        /**
         * 构建哈夫曼树
         * 建树是从最小权值开始的,所以借助小根堆
         */
        public void createHuffman(int[] weights) {
    
            // 构建小根堆,弹出是最小的元素
            Queue<Node> nodeQueue = new PriorityQueue<>();
            nodes = new Node[weights.length];
            for (int i = 0; i < weights.length; i++) {
                nodes[i] = new Node(weights[i]);
                nodeQueue.add(nodes[i]);
            }
    
            // 节点队列只剩一个节点结束,即根节点构建完成
            while (nodeQueue.size() > 1) {
    
                // 弹出权值最小的两个结点
                Node left = nodeQueue.poll();
                Node right = nodeQueue.poll();
    
                // 创建新节点作为两结点的父节点
                Node parent = new Node(left.weight + right.weight, left, right);
                nodeQueue.add(parent);
            }
    
            // 哈夫曼树根,遍历要用,优先级队列GC
            root = nodeQueue.poll();
            // 实现编码
            encode();
        }
    
        /**
         * 输入字符下标,输出对应的哈夫曼编码
         */
        public String convertHuffmanCode(int index) {
            return nodes[index].code;
        }
    
        /**
         * 递归填充二进制编码
         */
        private void encode() {
            encode(root, "");
        }
    
        private void encode(Node node, String code) {
            if (node == null) {
                return;
            }
            node.code = code;
            encode(node.left, node.code + "0");
            encode(node.right, node.code + "1");
        }
    
        /**
         * 测试
         */
        public static void main(String[] args) {
    
            // 字符及其对应权值
            char[] chars = {'A', 'B', 'C', 'D', 'E', 'F'};
            int[] weights = {2, 3, 7, 9, 18, 25};
    
            HuffmanCode huffManCode = new HuffmanCode();
            huffManCode.createHuffman(weights);
            for (int i = 0; i < chars.length; i++) {
                System.out.println(chars[i] + ":" + huffManCode.convertHuffmanCode(i));
            }
        }
    }
    
    


    2.4.2 传输实现

    • 将原文进行哈夫曼编码,记录字符及其对应的编码,保存文件为 HuffmanCode
    • 将原文的字符用哈夫曼编码代替,保存文件为 HuffmanText
    • 将上面两个文件发送给对方
    • 对方根据这两份文件就可以解码出原文




    3. 开源压缩框架


    3.1 图片

    Thumbnailator是专门压缩图片的,使用非常简洁

    // 图片压缩
    Thumbnails.of("C:\Users\Howl\Desktop\InPic.png")	// 输入图片地址
        .scale(1)											// 和原尺寸大小,即长度,1是原大小
        .outputQuality(0.5)									// 和原图的质量
        .outputFormat("jpg")								// 输出格式,png为高保真不会压缩
        .toFile("C:\Users\Howl\Desktop\OutPic");		// 输出地址
    }
    





    参考:

    程序员小灰



  • 相关阅读:
    linux apache + mysql +php no-yum
    linux apache + mysql +php
    1像素border
    vue-router配置
    错误Cannot find module 'stylus'
    高仿饿了么mock本地数据
    vue2.0高仿饿了么better-scroll
    npm 常用命令
    Gulp工具常用插件
    git总结
  • 原文地址:https://www.cnblogs.com/Howlet/p/15013233.html
Copyright © 2020-2023  润新知