由韩顺平老师的网课代码,其对哈夫曼树解码的最后一个字节可能会出现bug
在此提出解决方法,在压缩过程中多开辟一个空间用于存储最后一个字节的长度
这是全部代码
class HuffmanCode {
//哈夫曼编码对应map
private static Map<Byte, String> huffmanCodes = new HashMap<Byte, String>();
//stringBuilder用于拼接路径
private static StringBuilder stringBuilder = new StringBuilder();
public static List<Node> getNodes(String s) {
return getNodes(s.getBytes());
}
//根据数据生成一个列表
private static List<Node> getNodes(byte[] bytes) {
List<Node> list = new ArrayList<>();
Map<Byte, Integer> map = new HashMap<>();
for (int i = 0; i < bytes.length; i++) {
if (map.get(bytes[i]) == null) {
map.put(bytes[i], 1);
} else {
map.put(bytes[i], map.get(bytes[i]) + 1);
}
}
for (Map.Entry<Byte, Integer> byteIntegerEntry : map.entrySet()) {
list.add(new Node(byteIntegerEntry.getKey(), byteIntegerEntry.getValue()));
}
return list;
}
//根据列表生成一个哈夫曼树
public static Node createHuffmanTree(List<Node> list) {
while (list.size() > 1) {
Collections.sort(list);
Node node1 = list.remove(0);
Node node2 = list.remove(0);
Node node = new Node(null, node1.weight + node2.weight);
node.left = node1;
node.right = node2;
list.add(node);
}
return list.remove(0);
}
//获取编码
private static void getCodes(Node node, String code, StringBuilder stringBuilder) {
StringBuilder stringBuilder1 = new StringBuilder(stringBuilder);
stringBuilder1.append(code);
if (node != null) {
if (node.data == null) {
getCodes(node.left, "0", stringBuilder1);
getCodes(node.right, "1", stringBuilder1);
} else {
huffmanCodes.put(node.data, stringBuilder1.toString());
}
}
}
//重载一下
public static Map getCodes(Node root) {
if (root == null) {
return null;
}
getCodes(root.left, "0", stringBuilder);
getCodes(root.right, "1", stringBuilder);
return huffmanCodes;
}
//获取编码表【最终】
public static Map<Byte, String> get(String s) {
return getCodes(createHuffmanTree(getNodes(s)));
}
//压缩
public static byte[] zip(byte[] bytes, Map<Byte, String> huffmanCodes) {
StringBuilder stringBuilder1 = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
stringBuilder1.append(huffmanCodes.get(bytes[i]));
}
int len;
if (stringBuilder1.length() % 8 == 0) {
len = stringBuilder1.length() / 8;
} else {
len = stringBuilder1.length() / 8 + 1;
}
byte[] huffmanCodeBytes = new byte[len + 1];
int index = 0;
int length = 0;
for (int i = 0; i < stringBuilder1.length(); i += 8) {
String str;
if (i + 8 > stringBuilder1.length()) {
str = stringBuilder1.substring(i);
//huffmanCodeBytes最后一个空间存储 最后一个字符串的长度
length = str.length();
} else {
str = stringBuilder1.substring(i, i + 8);
}
huffmanCodeBytes[index] = (byte) Integer.parseInt(str, 2);
index++;
}
huffmanCodeBytes[index] = (byte) length;
//倒数第二个一定为正数,因为其的位数最多为七位
return huffmanCodeBytes;
}
//重载一下
public static byte[] zip(String s) {
return zip(s.getBytes(), huffmanCodes);
}
//解压
//生成对应的字符串
public static String byteToBitString(boolean flag, byte b) {
int tmp = b;
if (flag) {
tmp |= 256;
}
String str = Integer.toBinaryString(tmp);
return str.substring(str.length() - 8);
}
//正式解压
public static byte[] decode(byte[] huffmanCodeBytes) {
boolean flag = false;
StringBuilder stringBuilder1 = new StringBuilder();
for (int i = 0; i < huffmanCodeBytes.length - 1; i++) {
if (i == huffmanCodeBytes.length - 2) {
String string = new String();
string += Integer.toBinaryString(huffmanCodeBytes[i]);
while ((int) huffmanCodeBytes[i + 1] > string.length()) {
string = "0" + string;
}
stringBuilder1.append(string);
} else {
if (huffmanCodeBytes[i] >= 0) {
stringBuilder1.append(byteToBitString(true, huffmanCodeBytes[i]));
} else {
stringBuilder1.append(byteToBitString(false, huffmanCodeBytes[i]));
}
}
}
//把huffmanCodes倒置
Map<String, Byte> map = new HashMap<>();
for (Map.Entry<Byte, String> entry : huffmanCodes.entrySet()) {
map.put(entry.getValue(), entry.getKey());
}
List list = new ArrayList();
Byte b = null;
int count;
boolean loop = true;
String key;
int i = 0;
while (i < stringBuilder1.length()) {
count = 1;
loop = true;
while (loop) {
key = stringBuilder1.substring(i, i + count);
b = map.get(key);
if (b == null) {
count++;
} else {
loop = false;
}
}
list.add(b);
i = i + count;
}
byte[] bytes = new byte[list.size()];
for (int j = 0; j < bytes.length; j++) {
bytes[j] = (Byte) list.get(j);
}
return bytes;
}
}
class Node implements Comparable {
Byte data;
int weight;
Node left;
Node right;
public Node(Byte data, int weight) {
this.data = data;
this.weight = weight;
}
@Override
public int compareTo(Object o) {
return this.weight - ((Node) o).weight;
}
}