我的霍夫曼压缩程序应该能够压缩任何类型的文件。这就是为什么我使用FileInputStream从文件而不是字符中读取字节。
步骤1.创建的频率表是带有整数的数组。
/**
* Initialises field frequencyTable.
* Opens file, reads one byte at a time and counts each bytes frequency.
* @param file the file to be read.
*
*/
private void buildFrequencyTable(String file){
//since we are reading one byte at a time there are 256 possible values.
this.frequencyTable = new int[256];
try{
FileInputStream in = new FileInputStream(file);
int currentByte;
while((currentByte = in.read())!=-1){
//add that byte to frequencyTable and increment it.
this.frequencyTable[currentByte] ++;
}
}catch (IOException e){
e.printStackTrace();
}
}
步骤2:我创建霍夫曼树。
this.pq是优先级。PQ中的所有对象都是为每个唯一字节创建的节点。每个节点都有一个代表字节的整数值。以及代表该字节频率的另一个整数值。节点与它们的频率相当,因此在构建霍夫曼树时,使用较少的位等地编码了频率最高的字节。
节点类:
class Node implements Comparable<Node>{
private int value;
private int frequency;
private Node left_child;
private Node right_child;
Node(int value, int frequency, Node left_child, Node right_child){
this.value = value;
this.frequency = frequency;
this.left_child = left_child;
this.right_child = right_child;
}
//Checks if two nodes have equal frequency.
private boolean equals(Node n){
return this.frequency == n.frequency;
}
@Override
public int compareTo(Node other) {
if(this.equals(other)){
return 0;
}else if(this.frequency > other.frequency){
return 1;
}else return -1;
}
霍夫曼树建筑商方法:
private void createHuffmanTree(){
while(this.pq.size() > 1){
Node left = this.pq.poll();
Node right = this.pq.poll();
//null character means its not a leaf node.
Node parent = new Node(' ',left.getFrequency()+right.getFrequency(), left, right);
this.pq.add(parent);
}
//The last item in priority queue will be the final huffman tree node.
this.huffmanTree = this.pq.poll();
}
我的问题:
步骤3.进行压缩。
所以现在我准备了一棵霍夫曼树,可以用于创建原始文件的编码版本。但是我不明白这一步。
如果我创建了一个hashmap,将每个字节映射到其Huffman位编码。我是否在地图中将编码作为字符串放置?
等等,如果我创建了一种称为compress((的方法。我一次再次阅读原始文件一个字节。我将如何使用此hashmap来:1。从文件中找到currentbyte的键值,2.找到其相应的位编码(即字符串(,然后将这些单独的位写入另一个是压缩版本的文件?
例如。我有字节65(a(,并具有编码的" 11"。然后,压缩方法将输出:11 11 11(带有额外的填充(
注意!我得到了一些代码,这些代码实现了一个名为:bitfilereader的类。该课程读取文件,可以一次阅读。尽管我不知道如何在程序中使用此课程。
伪代码(非常(
void convert(InputStream in, BitFileWriter out) {
HuffmanTree huffman = new HuffmanTree()
int b;
while ((b = in.read()) != -1) {
huffman.add(b);
Bits bits = huffman.get(b);
for (int bit : bits.values()) {
out.writeBit(bit);
}
}
out.close();
}
位可能只是int[]
。或使用bitset:
class Bits {
final BitSet bitset;
final int nbits;
Bits(BitSet bitset, int nbits) {
this.bitset = bitset;
this.nbits = nbits;
}
int[] values() {
int[] v = new int[nbits];
for (int i = bitset.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
v[i] = 1;
}
return v;
}
}