数据结构之 Haffman编码

前面一篇博客已经介绍了什么是haffman树以及如何创建一棵haffman树。 这节我们将介绍 关于haffman树最重要的一个应用 haffman编码 它是一种压缩效率很高的算法。
比如我们有这样一个字符串 ABAC BDCE DFEG FACA CCDE FG
假如把这段字符串存储起来,按照UTF-8编码:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。每个字符是8个0和1,22 * 8 一共需要这么多个0 和1 表示。那如果我们用Haffman编码是多少个0 和1才能表示呢?
第一步、先统计字符的权重

ABCDEFG
4253332

按照权重我们排序结果是

BGDEFAC
2233345

按照上一节中我们的建树规则我们可以建一个这样的树

在这里插入图片描述
在这里插入图片描述
如上面的步骤 我们就建好了一个 haffman 树。 并且所有的左节点 标0 右节点标1,我们会得到这样的一个表

ABCDEFG
4253332
001110011001011101111

得到这个码表以后,我们可以根据这个码表进行重新的编码 ,我们用00 代表 A ,用1110 代表B
那么 ABAC BDCE DFEG FACA CCDE FG
得到的编码就是 00111000… -> ABA…

我编写一个测试代码验证一下


    /**
     * 根据表格的key和value 进行解码
     * @param strEncoder
     * @param table
     * @return
     */
    private String haffmanDecode(String strEncoder, TreeMap<String, String> table) {

        int i = 1;
        StringBuilder stringBuilder = new StringBuilder();
        while (strEncoder.length() > 0){

            String substring = strEncoder.substring(0, i);
            Set<Map.Entry<String, String>> entries = table.entrySet();
            for (Map.Entry<String, String> entry : entries) {
                if (entry.getValue().equals(substring)){
                    stringBuilder.append(entry.getKey());
                    strEncoder = strEncoder.substring(i);
                    i = 1;
                    continue;
                }
            }
            i++;
        }

        return stringBuilder.toString();
    }

    /**
     * 根据表格 key和value 进行编码
     * @param source
     * @param table
     * @return
     */
    private String haffmanEncode(String source, TreeMap<String, String> table) {
        int i =0 ;

        StringBuilder stringBuilder = new StringBuilder();
        while (i < source.length()){
            char c = source.charAt(i);
            String key = String.valueOf(c);
            String s = table.get(key);
            stringBuilder.append(s);
            i++;
        }
        return stringBuilder.toString();
    }
    @Test
    public void testHaffmanCodec(){
        String source = "ABACBDCEDFEGFACACCDEFG";

        //码表
        TreeMap<String,String> table = new TreeMap<>();
        table.put("A","00");
        table.put("B","1110");
        table.put("C","01");
        table.put("D","100");
        table.put("E","101");
        table.put("F","110");
        table.put("G","1111");

        //编码后字符串是
        String strEncode =  haffmanEncode(source,table);
        System.out.println(strEncode);
        String strDecode = haffmanDecode(strEncode,table);
        System.out.println(strDecode);
        
        System.out.println("数据原本的大小是 "+(source.length() * 8));
        System.out.println("编码后的大小是 "+(strEncode.length()));
    }

输出结果:
0011100001111010001101100110101111111000010001011001011101111
ABACBDCEDFEGFACACCDEFG
数据原本的大小是 176
编码后的大小是 61

这样原本需要176个字符表示的数据, 现在我们只需要 61个0和1表示。 压缩的体积达到了50%以上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值