我在确定每个包含char的节点的优先级以解压缩压缩文件时遇到问题。
所以当我压缩文件时,它会给我一个包含如下内容的txt文件:
我压缩了:世界您好,这是一个测试。
@ 111 ^ a @ 10000 ^#@ 10001 ^ d @ 10011 ^ e @ 1010 ^ H @ 0000 ^ h @ 10110 ^ i @ 1101 ^ l @ 001 ^。@ 0001 ^ o @ 1100 ^ r @ 10010 ^ s @ 011 ^ t @ 010 ^ w @ 10111 ^%
00001010001001110011110111110010010001100111110101011011010111111101011111100001110101010011010000110001
前两行具有压缩文件中包含的每个字符的二进制表示形式。
后两行是实际的压缩txt。
压缩类通过将节点的优先级设置为等于出现次数来创建树。
但是,压缩类不会将每个字符的出现次数写入输出文件。
为了确定优先级,我想我可以通过每个字符的二进制字符串的长度来做到这一点。如果字符串的长度较大,则使用频率较低。另一方面,如果较小,则使用更多。 但是,这似乎并没有按照我想要的方式构造树,因为它给了我错误的输出。
通过编辑压缩文件写入输出文件的内容,我能够获得正确的输出。基本上也只是传递字符频率。但是,如果没有这些价值观,我该怎么办呢?
我还认为我可以根据每个字符的实际Binary字符串来制作树。创建虚拟根节点之类的东西。如果字符串中的charAt(i)等于0,则向左移动,否则向右移动。我认为我的代码对此可能有点过时,因为在尝试遍历树时出现空指针异常。会在下面发布代码。
这是一个简短的简单版本,如有需要,我可以发表更多
public class Decompress {
private static Node root;
private static HashMap<Character, String> values = new HashMap<Character, String>();
private static HashMap<Character, Integer> freq = new HashMap<Character, Integer>();
public Decompress() {
root = null;
}
private static class Node implements Comparable {
public Character value;
public Integer number;
public Node left;
public Node right;
// necessary in order for the priority queue to work
// since it uses the compareTo to determine priority.
public int compareTo(Object o) {
Node other = (Node) o;
if (other.number < number) {
return 1;
}
if (other.number == number) {
return 0;
}
return -1;
}
public static void main(String args[]) throws IOException {
BufferedReader fin = new BufferedReader(new FileReader("output" + ".txt"));
String binaryDigits = insertListHelper(fin); // contains the compressed txt
root = createTree(binaryDigits); // Grabs the root node from method
Node hold = root;
// code for traversing the tree to find the character
for (int i = 0; i < binaryDigits.length(); i++) {
if (binaryDigits.charAt(i) == '1') {
root = root.right;
} else if (binaryDigits.charAt(i) == '0') {
root = root.left;
}
if (root.left == null && root.right == null) {
System.out.println(root.value);
root = hold;
}
}
}
// works when I have the correct frequency
public static Node createTree(String binaryDigit) {
PriorityQueue<Node> pq = new PriorityQueue<Node>();
// insert all 1 node trees into pq
Set<Character> s = values.keySet();
for (Character c : s) {
Node temp = new Node();
temp.value = c;
temp.number = values.get(c).length();
temp.left = null;
temp.right = null;
pq.add(temp);
}
Node eof = new Node();
eof.value = '#';
eof.number = 1;
eof.left = null;
eof.right = null;
pq.add(eof);
while (pq.size() > 1) {
Node left = pq.poll();
Node right = pq.poll();
Node temp = new Node();
temp.value = null;
temp.number = left.number + right.number;
temp.left = left;
temp.right = right;
pq.add(temp);
}
return pq.peek();
}
// does not work any suggestions?
public static Node createTree2() {
String[] binaryRep = new String[values.size()];
int k = 0;
int lengthOfStr = 0;
Set<Character> s1 = values.keySet();
for (Character c : s1) {
binaryRep[k] = values.get(c);
System.out.println(c + " String : " + binaryRep[k]);
Node root = new Node();
root.value = 'R';
root.left = null;
root.right = null;
Node hold = root;
lengthOfStr = binaryRep[k].length();
for (int i = 0; i < binaryRep[k].length(); i++) {
if (binaryRep[k].charAt(i) == '1' && root.right != null) {
root = root.right;
} else if (binaryRep[k].charAt(i) == '0' && root.left != null) {
root = root.left;
} else if (binaryRep[k].charAt(i) == '1' && root.right == null && lengthOfStr == 0) {
// found our place to insert
Node temp = new Node();
temp.left = null;
temp.right = null;
temp.number = 1;
temp.value = c;
root.right = temp;
// move forward to the temp var
root = root.right;
root = hold;
lengthOfStr--;
} else if (binaryRep[k].charAt(i) == '0' && root.left == null && lengthOfStr == 0) { // should be a leaf
// node
// found our place to insert
Node temp = new Node();
temp.left = null;
temp.right = null;
temp.number = 0;
temp.value = c;
root.left = temp;
// move forward to the temp var
root = root.right;
root = hold;
lengthOfStr--;
} else if (binaryRep[k].charAt(i) == '1' && root.right == null) {
// found our place to insert
Node temp = new Node();
temp.left = null;
temp.right = null;
temp.number = 1;
temp.value = null;
root.right = temp;
// move forward to the temp var
root = root.right;
lengthOfStr--;
} else if (binaryRep[k].charAt(i) == '0' && root.left == null) {
// found our place to insert
Node temp = new Node();
temp.left = null;
temp.right = null;
temp.number = 0;
temp.value = null;
root.left = temp;
// move forward to the temp var
root = root.left;
lengthOfStr--;
}
}
k++;
}
return root;
}
}
答案 0 :(得分:0)
您在正确的轨道上,您可以通过每个字符的二进制字符串的长度来做到这一点。 许多执行霍夫曼压缩的程序会在文件的开头(或文件大块的开头)存储一个简短的标头。 通常,压缩器和解压缩器同意使用“ canonical Huffman codes”。 然后,标头仅需要存储在明文中实际使用的符号,以及每个符号的霍夫曼代码的长度(以位为单位)。
仅给出明文中使用的符号及其排名,就不可能对霍夫曼压缩文件进行解码。如果您有5个不同的符号,则霍夫曼树将包含5个不同的比特序列-但是,霍夫曼算法生成的确切比特序列取决于确切的频率。一个文档的符号计数可能为{10、10、20、40、80},从而导致霍夫曼比特序列{0000 0001 001 01 1}。另一个文档的符号计数可能为{40,40,79,79,80},从而导致霍夫曼比特序列{000 001 01 10 11}。即使这两种情况都恰好有5个唯一的符号(以相同的顺序排列),但在这两个压缩文档中,最频繁使用的符号的实际霍夫曼代码却大不相同-一个文档中的霍夫曼代码为“ 1”,霍夫曼代码为“ 11”在另一个文档中。 (Maximum number of different numbers, Huffman Compression)。
相关: