Java でハフマン エンコーディング アルゴリズムを実装しました。プライオリティ キューを使用して、ルートからリーフまでツリーをトラバースし、シンボルが入力に現れる回数に基づいて #=000011 としてエンコーディング例を取得します。すべて問題なく、ツリーは正常に構築されており、エンコーディングは期待どおりです。しかし、取得している出力ファイルは元のファイルよりもサイズが大きくなっています。現在、ツリーの左側のノードと右側のノードをトラバースするときに、文字列に「0」と「1」を追加しています。おそらく、最終的には各文字に 8 ビットすべてを使用することになり、圧縮には役立ちません。これらのビットを必要な文字値に変換する必要があると推測しています。これらの文字が使用するビット数が 8 より少ないため、元のファイルの圧縮バージョンが得られます。Javaで文字を操作してビットを減らすことで圧縮を達成する方法を教えてください。ありがとう
1 に答える
おそらく、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;
}
}
もちろん、一度に 1 バイトずつ書き込むのは非効率的です。さらに、OutputStream インターフェイスはバイト配列しか受け入れません ( byte[]
)。List
したがって、バイトを配列 (またはさらに簡単に a ) に格納してから、より大きなチャンクで書き込む方がよいでしょう。
バイト書き込みの使用が許可されていない場合 (なぜそうならないのか? ObjectOutputStream はバイト配列の書き込みをサポートしています!)、Base64 を使用してバイナリ文字列をエンコードできます。ただし、Base64 ではデータ使用量が 33% 増加することに注意してください。
バイト配列を base64 に変換する簡単な方法は、既存のエンコーダーを使用することです。次のインポートを追加した後:
import sun.misc.BASE64Encoder;
エンコーダーをインスタンス化し、バイト配列を文字列に変換できます。
byte[] bytes = getBytesFromHuffmanEncoding();
BASE64Encoder encoder = new BASE64Encoder();
String encodedString = encoder.encode(bytes);