哈夫曼编码(下)


在这里插入图片描述

问题引入

继上章,我们学会了哈夫曼编码的编写,那么我们如何将哈夫曼编码转会原来的字符串?,这章我们将进入介绍。

哈夫曼解码的编写

总述
1.将哈夫曼编码重新写为哈夫曼编码对应的二进制字符串
2.将哈夫曼编码对应的二进制字符串对照哈夫曼编码恢复原字符串

步骤一

首先我们需要将哈夫曼编码转变成哈夫曼编码对应的二进制字符串。
由于每个哈夫曼编码都是一个字节(最后一个可能不是一个字节,上章在步骤四有介绍),所有我们需要将字节转换为字节转化为一个二进制的字符串,当所有哈夫曼编码的字节对应的二进制编码连接在一起,就是我们需要的二进制字符串。
以下的decode方法还是一个雏形,只是将哈夫曼编码转变成哈夫曼编码对应的二进制字符串,执行完decode后stringBuilder里面放着的即是我们需要的二进制字符串。

在这里插入图片描述

//将一个byte 转为一个二进制的字符串
private static String byteToBitString(boolean flag,byte b){
        //使用变量保存b
        int temp = b;
        //如果是正整数还存在部高位的问题
        if(flag){
            temp |= 256; //按位与 1 0000 0000 | 0000 0001 => 1 0000 0001
        }

        String str = Integer.toBinaryString(temp); //返回的是temp对应的二进制的补码
        if(flag){
            return str.substring(str.length() - 8);
        }else {
            return str;
        }
    }
//获得哈夫曼编码对应的二进制字符串
 private static byte[] decode(Map<Byte,String> huffmanCodes,byte[] huffmanBytes){
        //1.先得到 huffmanBytes 对应的二进制的字符串,形式101010000...
        StringBuilder stringBuilder = new StringBuilder();
        //将byte数组转为二进制的字符串
        for (int i = 0; i < huffmanBytes.length; i++) {
            //判断是否为最后一个字节
            boolean flag = (i == huffmanBytes.length - 1);
            stringBuilder.append(byteToBitString(!flag,huffmanBytes[i]));
        }
} 

步骤二

将哈夫曼编码对应的二进制字符串对照哈夫曼编码恢复原字符串。
接下来我们继续完善decode方法。以上的decode有两个参数,一个是Map<Byte,String> huffmanCodes,即我们编写的哈夫曼编码表,另一个是byte[] huffmanBytes,即存放哈夫曼编码的字节数组。
我们将huffmanCodes编码表进行调换,因为我们需要反向编码,即用字符串中的数字来对应字符串中的字符。
最后我们将所得到的字符串放入list集合中,所有我们创建一个List list = new ArrayList<>();,存放byte.
接下来我们需要遍历stringBuilder得到对应的字符串,将得到的每一个字符放入list中,然后将list中的每个字符再放入字符数组byte[] b = new byte[list.size()]中,然后返回。
在这里插入图片描述
完整的decode方法如下:

//将哈夫曼编码解码
 private static byte[] decode(Map<Byte,String> huffmanCodes,byte[] huffmanBytes){
        //1.先得到 huffmanBytes 对应的二进制的字符串,形式101010000...
        StringBuilder stringBuilder = new StringBuilder();
        //将byte数组转为二进制的字符串
        for (int i = 0; i < huffmanBytes.length; i++) {
            //判断是否为最后一个字节
            boolean flag = (i == huffmanBytes.length - 1);
            stringBuilder.append(byteToBitString(!flag,huffmanBytes[i]));
        }
        //把字符串按照指定的赫夫曼编码进行解码
        //把赫夫曼编码表进行调换,因为反向查询 a->100 100->a
        Map<String,Byte> map = new HashMap<String,Byte>();
        for (Map.Entry<Byte, String> entry : huffmanCodes.entrySet()) {
            map.put(entry.getValue(),entry.getKey());
        }

        //创建一个集合,存放byte
        List<Byte> list = new ArrayList<>();
        for (int i = 0; i < stringBuilder.length();) {
            int count = 1; //小的计数器
            boolean flag = true;
            Byte b = null;

            while (flag){
                String key = stringBuilder.substring(i,i + count);
                b = map.get(key);
                if(b == null){
                    count++;
                }else {
                    flag = false;
                }
            }
            list.add(b);
            i += count; 
        }

        //当for循环结束后,我们从list中就存放所有的字符 "i like like like java do you like a java"
        //把list中的数据放入byte[] 并返回
        byte[] b = new byte[list.size()];
        for (int i = 0; i < b.length; i++) {
            b[i] = list.get(i);
        }
        return b;
    }

完整代码如下


public class HuffmanCode {

    public static void main(String[] args) {
        //以下为将指定字符串用赫夫曼编码转为字节数组的过程,并将该字节数组转为原字符串
        String str = "i like like like java do you like a java";
        byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
        byte[] huffmanCodeBytes = huffmanZip(bytes);

        System.out.println("压缩后的结果为 : " + Arrays.toString(huffmanCodeBytes));

		//上述方法在上章已经编写完成,需要大家copy一下到此文件中,不然会报错.
		//下面是已经编写好的方法。
        byte[] sourceBytes = decode(buffmanCodes, huffmanCodeBytes);
        System.out.println("原来的字符串: " + new String(sourceBytes));

    }
    //将哈夫曼编码解码
    private static byte[] decode(Map<Byte,String> huffmanCodes, byte[] huffmanBytes){
        //1.先得到 huffmanBytes 对应的二进制的字符串,形式101010000...
        StringBuilder stringBuilder = new StringBuilder();
        //将byte数组转为二进制的字符串
        for (int i = 0; i < huffmanBytes.length; i++) {
            //判断是否为最后一个字节
            boolean flag = (i == huffmanBytes.length - 1);
            stringBuilder.append(byteToBitString(!flag,huffmanBytes[i]));
        }
        //把字符串按照指定的赫夫曼编码进行解码
        //把赫夫曼编码表进行调换,因为反向查询 a->100 100->a
        Map<String,Byte> map = new HashMap<String,Byte>();
        for (Map.Entry<Byte, String> entry : huffmanCodes.entrySet()) {
            map.put(entry.getValue(),entry.getKey());
        }

        //创建一个集合,存放byte
        List<Byte> list = new ArrayList<>();
        for (int i = 0; i < stringBuilder.length();) {
            int count = 1; //小的计数器
            boolean flag = true;
            Byte b = null;

            while (flag){
                String key = stringBuilder.substring(i,i + count);
                b = map.get(key);
                if(b == null){
                    count++;
                }else {
                    flag = false;
                }
            }
            list.add(b);
            i += count;
        }

        //当for循环结束后,我们从list中就存放所有的字符 "i like like like java do you like a java"
        //把list中的数据放入byte[] 并返回
        byte[] b = new byte[list.size()];
        for (int i = 0; i < b.length; i++) {
            b[i] = list.get(i);
        }
        return b;
    }
    //将一个byte 转为一个二进制的字符串
    private static String byteToBitString(boolean flag,byte b){
        //使用变量保存b
        int temp = b;
        //如果是正整数还存在部高位的问题
        if(flag){
            temp |= 256; //按位与 1 0000 0000 | 0000 0001 => 1 0000 0001
        }

        String str = Integer.toBinaryString(temp); //返回的是temp对应的二进制的补码
        if(flag){
            return str.substring(str.length() - 8);
        }else {
            return str;
        }
    }
}

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值