上篇文章讲到了哈夫曼编码的压缩,但是只会压缩不会解压缩也没什么用。接下来就来说一说哈夫曼编码的解压缩。
仍以下面这句话为例:“oh my god! oh my god! hey”;当我们获得压缩过的字节数组后,需要对该字节数组转换为2进制的字符串。
即转换为: 110 001 01 1011 100 01 1110 110 1111 000 01 110 001 01 1011 100 01 1110 110 1111 000 01 001 1010 100。
通过已经得到过的编码表:
o:110 h:001 m:1011 y:100 g:1110 d:1111 e:1010
!:000 空格:01
将二进制对应的编码转换为字符即可。
代码实现:
/**
* 解压缩
* @param map 哈夫曼编码表
* @param bytes 压缩后的字节数组
* @param sourceBytesLength 未压缩字节数组的长度
*/
public static void decode(Map<Byte, String> map, byte[] bytes, int sourceBytesLength) {
StringBuilder stringBuilder = new StringBuilder();
Map<String, Byte> mapReverse = new HashMap<>();
byte[] sourceBytes = new byte[sourceBytesLength];
//将编码表反转,即key与value对换。
for (Map.Entry<Byte, String> entry : map.entrySet()) {
mapReverse.put(entry.getValue(), entry.getKey());
}
//将字节数组转换为二进制字符串
for (int i = 0; i < bytes.length; i++) {
byte b = bytes[i];
boolean flag = (i == bytes.length - 1);
//将字节数组中的每个字节转换为二进制
String string = byteToBitString(!flag, b);
stringBuilder.append(string);
}
//解压缩
int index = 1;
int j = 0;
for (int i = 0; i < stringBuilder.length();) {
String substring = stringBuilder.substring(i, index);
Byte aByte = mapReverse.get(substring);
if (aByte != null) {
sourceBytes[j] = aByte;
j++;
i = index;
}
index++;
}
System.out.println(new String(sourceBytes));
}
/**
* 将字节转换为二进制
* @param flag
* @param b
* @return
*/
public static String byteToBitString(boolean flag, byte b) {
int temp = b;
if (flag) {
temp |= 256;
}
String string = Integer.toBinaryString(temp);
//endLength为静态变量
if (string.length() < endLength) {
int length = endLength - string.length();
for (int i = 0; i < length; i++) {
string = '0' + string;
}
}
if (flag) {
return string.substring(string.length() - 8);
} else {
return string;
}
}