四方显神

导航

数据结构020_赫夫曼解码

数据解压就是数据压缩的逆向。

直接上代码:

    /**
     * 数据解压 思路: 1.将huffmanCodeByte[-88, -65, -56, -65, -56, -65, -55, 77, -57,
     * 6, -24, -14, -117, -4, -60, -90, 28] 重新先转成赫夫曼编码对应的二进制字符串“10101000...”
     * 2.赫夫曼编码对应的二进制字符串“1010100....” => 对照赫夫曼编码 => "i like like...."
     */

    /**
     * 功能:(数据解压第一步)将一个byte转成一个二进制的字符串
     * 
     * @param b
     *            传入的byte
     * @param flag
     *            标识是否需要补高位,true表示需要补高位,false不需要.如果是最后一个字节不需要补高位。
     * @return 是该byte对应的二进制字符串(注意是按补码返回的)
     */
    private static String byteToBitString(boolean flag, byte b) {
        // 使用变量保存b,将b转成int使用integer的toBinaryString
        int temp = b;

        if (flag) {
            // 正数还存在补高位
            temp |= 256; // 按位与 256(1 0000 0000) 1(0000 0001) 按位与=> 1 0000 0001
        }

        String str = Integer.toBinaryString(temp);// 这里返回的是temp对应的二进制的补码

        if (flag)
            return str.substring(str.length() - 8);
        else
            return str;
    }

    /**
     * 功能:(数据解压第二步 核心代码)解码
     * 
     * @param huffmanCodes
     *            赫夫曼编码表
     * @param huffmanBytes
     *            赫夫曼编码得到的字节数组
     * @return 就是原来的字符串对应的数组
     */
    private static byte[] decode(Map<Byte, String> huffmanCodes, byte[] huffmanBytes) {
        // 1.先得到huffmanByte对应的二进制字符串,形式“1010100...”
        StringBuilder sb = new StringBuilder();
        // 2.将byte数组转换成二进制字符串
        for (int i = 0; i < huffmanBytes.length; i++) {
            byte b = huffmanBytes[i];
            boolean flag = (i == huffmanBytes.length - 1); // 最后一位不用补位 这里还可以这样写呀
            sb.append(byteToBitString(!flag, b));
        }
        // System.out.println("赫夫曼字节数组对应的二进制字符串="+sb.toString());

        // 把字符串按照指定的赫夫曼编码进行解码
        // 把赫夫曼编码表进行调换,因为要反向查询(原先97->100,现在100->97)
        Map<String, Byte> map = new HashMap<String, Byte>();
        for (Map.Entry<Byte, String> entry : huffmanCodes.entrySet()) {
            map.put(entry.getValue(), entry.getKey());
        }
        // 大概就是map={000=108, 01=32, 100=97, 101=105, 11010=121, 0011=111,
        // 1111=107, 11001=117, 1110=101, 11000=100, 11011=118, 0010=106}

        // 创建一个集合,存放byte
        List<Byte> list = new ArrayList<>();
        for (int i = 0; i < sb.length();) { // i可以理解成一个索引,扫描sb
                                            // 【这里循环可以不写步长的唉,第一次】
            int count = 1;// 小的计数器
            boolean flag = true;
            Byte b = null;

            while (flag) {
                // 递增地取出key,就是1,10,101,...直到匹配到
                String key = sb.substring(i, i + count);// i不懂,让count走,直到匹配到一个字符
                b = map.get(key);
                if (b == null) // 没有匹配到
                    count++;
                else // 匹配到
                    flag = false;
            }
            list.add(b);
            i += count;
        }
        // 当for循环结束后,list中就存放了所有的字符
        // 把list中的数据放入一个byte[]并返回
        byte b[] = new byte[list.size()];
        for (int i = 0; i < b.length; i++) {
            b[i] = list.get(i);
        }
        return b;

    }

 

posted on 2020-11-20 07:53  szdbjooo  阅读(54)  评论(0编辑  收藏  举报