huffman编码压缩与解码bug处理

huffman编码压缩与解压

学习huffman编码后,了解了网络上主流的编码压缩和解码方式。但解压代码中存在一些bug,在这里和大家分享一下解决方法。


bug如下:

解压时,最后一个字节转成二进制时,位数的不确定性可能导致解压后字符串错误。比如,byte 存储为1,原先的编码后的字符串最后几位可能为 001 或者 0001。使用Integer中的字节转换二进制,解析byte1,正数只会返回1,此时如果不做处理,解码后的字符串可能会少0,可能报异常或者解压错误

解决方法:
  1. 思路:单独处理最后一个byte,还是按照原先的方式先转化成二进制字符串,然后与原先编码获得的字符串比较长度,如果相等,那就直接拼接,如果不相等,那就先末端补0,同时比较,直到解压后的字符串长度和编码后的字符串长度一致。
  2. 处理bug部分代码如下:
// 首先转化成二进制符号,然后拼接成字符串-注意末尾byte的处理
		StringBuilder str = new StringBuilder();
		boolean flag;
		byte b;
		for (int i = 0; i < huffmanBytes.length - 1; i++) {
			// 判断是否被8整除,如果整除就不用判断最后一个数据,全部需要补位截取
			b = huffmanBytes[i];
			str.append(byteToBinary(true, b));
		}
		// 单独处理一下最后一位byte
		b = huffmanBytes[huffmanBytes.length - 1];
		String lastByteStr = byteToBinary(false, b);
		// 如果长度相等,那正好。拼接上去
		if (str.length() + lastByteStr.length() == huffmanCodesStr.length()) {
			str.append(lastByteStr);
		} else {
			// 如果长度不够,那就先补0,直到总长度相等,再拼接
			while (str.length() + lastByteStr.length() < huffmanCodesStr.length()) {
				str.append(0);
			}
			str.append(lastByteStr);
		}

完整代码供大家参考:

解压及byte转化成二进制代码如下:

	// 解压
	public static byte[] decode(byte[] huffmanBytes, Map<Byte, String> pathCodes) {
		// 首先转化成二进制符号,然后拼接成字符串-注意末尾byte的处理
		StringBuilder str = new StringBuilder();
		boolean flag;
		byte b;
		for (int i = 0; i < huffmanBytes.length - 1; i++) {
			// 判断是否被8整除,如果整除就不用判断最后一个数据,全部需要补位截取
			b = huffmanBytes[i];
			str.append(byteToBinary(true, b));
		}
		// 单独处理一下最后一位byte
		b = huffmanBytes[huffmanBytes.length - 1];
		String lastByteStr = byteToBinary(false, b);
		// 如果长度相等,那正好。拼接上去
		if (str.length() + lastByteStr.length() == huffmanCodesStr.length()) {
			str.append(lastByteStr);
		} else {
			// 如果长度不够,那就先补0,直到总长度相等,再拼接
			while (str.length() + lastByteStr.length() < huffmanCodesStr.length()) {
				str.append(0);
			}
			str.append(lastByteStr);
		}
		System.out.println("解码后的哈夫曼编码字符串为:" + str.toString() + "长度为:"+ str.length());
		// 然后对应原先的map表 i=100 反转 制定新的map表 100 =i
		Map<String, Byte> map = new HashMap<String, Byte>();
		for (Map.Entry<Byte, String> entry : pathCodes.entrySet()) {
			map.put(entry.getValue(), entry.getKey());
		}
		// 扫描上面的code字符串,对应出单词空格保存到list中
		List<Byte> list = new ArrayList<>();
		for (int j = 0; j < str.length();) {
			// i只是前进所用,真正扫描寻找到有为止,还需要一个索引
			int count = 1;
			// 遍历查找的结束标识
			boolean flag2 = true;
			String subStr = null;
			// 注意越界判断
			while (flag2 && (j + count) <= str.length()) {
				// 截取子串,进行map中key值比较
				subStr = str.substring(j, j + count);
				// b2 = map.get(subStr);
				if (map.containsKey(subStr)) {
					flag2 = false;
				} else {
					// 没有的话继续遍历后移
					count++;
				}
			}
			// 将这个byte添加到list中
			list.add(map.get(subStr));
			// 查找到一个后,后移到下一个j起始处.此处后移了j那么for中就不要再后移了
			j += count;
		}
		// 扫描完所有的字符串,将list中的数据转化成byte[]
		byte[] bt = new byte[list.size()];
		for (int i = 0; i < bt.length; i++) {
			bt[i] = list.get(i);
		}
		return bt;

	}
	// 首先需要一个将byte转化为电脑储存的补码二进制形式的方法
	/**
	 * @param flag
	 *            传进来的字符串中是否末尾的标识 末尾不一定有8位长,直接补齐8位可能出错。所以不在这里补齐 比如 0100 00100
	 *            都是4 但是我们返回100即可,补齐的问题交给解压方法
	 * @param b
	 *            需要转化的字节数
	 * @return
	 */
	public static String byteToBinary(boolean flag, byte b) {
		// Integer中有直接转化成二进制的方法
		// 转化类型
		int num = b;
		// 转化
		// 正数转化呢,只有后几位,---所以需要补位0 补齐8 位
		// 256 1 0000 0000 与256或计算,就可以得到后八位长度 负数不影响,只要后8位
		if (flag) {
			num |= 256;
		}
		String binaryStr = Integer.toBinaryString(num);
		if (flag || num < 0) {
			// true 就是还没到末尾 都是8位 以及负数的情况
			// 但是注意!负数转化完是int类型32位的二进制补码--所以需要取出后8位
			return binaryStr.substring(binaryStr.length() - 8);

		} else {
			// false 到了末尾值,正数,不足8位,直接返回该有的长度就可以。
			return binaryStr;
		}
	}

完整的整个编码压缩过程请到这里:
huffman编码实现数据压缩

  • 15
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值