19.赫夫曼编码和数据压缩

赫夫曼编码

赫夫曼编码是一种变长编码方式,在通信中是一种经典的应用。广泛用于文件压缩,压缩率通常在20%~90%之间,主要通过使用的频率在最大化节约字符的存储空间。

实现步骤

  1. 统计各个字符的使用次数,用一个Node节点保存起来,具体data属性为字符对应的byte,weight权重代表他出现的次数
  2. 根据上述统计构建赫夫曼树
  3. 根据构建的赫夫曼树约定编码向左路径为0,右路径为1
  4. 单独创建一个全局的赫夫曼码表Map<byte,String> key为字符对应的byte String是该字符在这个赫夫曼树上的路径 由0和1拼接的字符串
  5. 递归赫夫曼树将所有叶子节点 记录节点的路径 添加赫夫曼码表中
  6. 如果要实现数据压缩,根据原文去赫夫曼码表中找对应的赫夫曼编码,拼接成一个新的编码,新生成的赫夫曼编码8位一个字节封装到一个byte数组中即可完成压缩

代码实现

public class HuffmanCodeDemo {

    public static void main(String[] args) {
        String content = "i like like like java do you like a java";
        System.out.println(Arrays.toString(zip(content)));
    }

    /**
     * 赫夫曼码表
     */
    public static Map<Byte, String> huffmanCodeMap = new HashMap<>();

    /**
     * 得到赫夫曼编码并压缩的方法整合
     *
     * @param content
     * @return
     */
    public static byte[] zip(String content) {
        HuffmanNode huffmanTree = createHuffmanNode(content);
        getHuffmanCode(huffmanTree, "");
        return getHuffmanZipCode(content.getBytes(), huffmanCodeMap);
    }

    /**
     * @param content        原始文本的byte
     * @param huffmanCodeMap
     * @return
     */
    public static byte[] getHuffmanZipCode(byte[] content, Map<Byte, String> huffmanCodeMap) {
        // 1. 将原始字符串的字节数从对应的赫夫曼码表中找 然后拼接成一个新的字符串
        StringBuilder builder = new StringBuilder();
        for (byte b : content) {
            builder.append(huffmanCodeMap.get(b));
        }
        // 2.每8位封装成一个byte数字 先获取数组长度
        int len;
        if (builder.length() % 8 == 0) {
            len = builder.length() / 8;
        } else {
            len = builder.length() / 8 + 1;
        }
        byte[] zipContent = new byte[len];
        int index = 0;
        for (int i = 0; i < builder.length(); i += 8) {
            String subContent;
            if (i + 8 > builder.length()) {
                subContent = builder.substring(i);
            } else {
                subContent = builder.substring(i, i + 8);
            }
            zipContent[index++] = (byte) Integer.parseInt(subContent, 2);
        }
        return zipContent;
    }

    /**
     * 根据赫夫曼树生成赫夫曼编码 规定向左为0 向右为1
     *
     * @param node 赫夫曼树
     * @param code 原始赫夫曼编码
     * @return
     */
    public static void getHuffmanCode(HuffmanNode node, String code) {
        if (node != null) {
            // 非数据节点
            if (node.data == null) {
                // 向左递归
                // 向右递归
                getHuffmanCode(node.left, code + "0");
                getHuffmanCode(node.right, code + "1");
            } else {
                huffmanCodeMap.put((byte) node.data, code);
            }
        }
    }

    /**
     * 将传入的字符串 拆分成byte 统计 每个byte 出现的次数然后生成一颗赫夫曼树
     *
     * @param content
     * @return
     */
    public static HuffmanNode createHuffmanNode(String content) {
        if (null == content || content.length() == 0) {
            return null;
        }
        // 1. 字符出现次数统计
        Map<Byte, Integer> wordCount = new HashMap<>();
        byte[] bytes = content.getBytes();
        for (byte b : bytes) {
            if (wordCount.get(b) == null) {
                wordCount.put(b, 1);
            } else {
                wordCount.put(b, wordCount.get(b) + 1);
            }
        }
        // 2. 将统计出来的字符串转成一个Node集合中用于生成 赫夫曼树
        List<HuffmanNode> huffmanNodes = new ArrayList<>();
        for (Byte key : wordCount.keySet()) {
            huffmanNodes.add(new HuffmanNode(key, wordCount.get(key)));
        }
        // 3. 将Node集合构建成一颗赫夫曼树
        while (huffmanNodes.size() > 1) {
            Collections.sort(huffmanNodes);
            HuffmanNode leftNode = huffmanNodes.get(0);
            HuffmanNode rightNode = huffmanNodes.get(1);
            HuffmanNode parent = new HuffmanNode(null, leftNode.weight + rightNode.weight);
            parent.left = leftNode;
            parent.right = rightNode;
            huffmanNodes.remove(leftNode);
            huffmanNodes.remove(rightNode);
            huffmanNodes.add(parent);
        }
        return huffmanNodes.get(0);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值