我已经使用优先级队列在Java中实现了霍夫曼编码算法,其中我将树从根遍历到叶子,并根据符号在输入中出现的次数获得#= 000011的编码示例。一切都很好,树正在构建正常,编码正如预期:但我得到的输出文件比原始文件更大。我目前正追加'0'和遍历树的左节点和右节点的字符串'1'。可能我最终会使用每个字符的所有8位,这对压缩没有帮助。我猜这些位有一些转换为需要的字符值。因此,这些字符使用的位数少于8,因此我获得了原始文件的压缩版本。你能告诉我如何通过操纵字符和减少Java中的位来实现压缩吗?谢谢
答案 0 :(得分:0)
您可能正在使用StringBuilder并附加“0”或“1”,或者仅使用+
运算符将“0”或“1”连接到字符串的末尾。或者你正在使用某种OutputStream
并写信给它。
您要做的是写出实际位。我建议在写之前先制作一个完整的字节。一个字节如下所示:
0x05
哪个代表二进制字符串0000 0011
。
您可以通过制作byte
类型,添加和转移来制作这些:
public void writeToFile(String binaryString, OutputStream os){
int pos = 0;
while(pos < binaryString.length()){
byte nextByte = 0x00;
for(int i=0;i<8 && pos+i < binaryString.length(); i++){
nextByte << 1;
nextByte += binaryString.charAt(pos+i)=='0'?0x0:0x1;
}
os.write(nextByte);
pos+=8;
}
}
当然,一次写入一个字节效率很低,而且最重要的是OutputStream接口只接受字节数组(byte[]
)。因此,最好将字节存储在数组中(或者更容易,List
),然后将它们写在更大的块中。
如果不允许使用字节写入(为什么不能?ObjectOutputStream支持编写字节数组!),那么您可以使用Base64对二进制字符串进行编码。但请记住,Base64会将您的数据使用率提高33%。
将字节数组转换为base64的简便方法是使用现有的编码器。添加以下导入后:
import sun.misc.BASE64Encoder;
您可以实例化编码器并将字节数组转换为字符串:
byte[] bytes = getBytesFromHuffmanEncoding();
BASE64Encoder encoder = new BASE64Encoder();
String encodedString = encoder.encode(bytes);