ほぼ確実に、ツリー自体を保存する必要はありません。あなたはそうすることができます、そしてそれはあなたがそうすると思うスペースを取るべきではありません、しかしそれは一般的に必要ではありません。
ハフマンコードが正規の場合、正規のコーディングを生成するために必要なすべての情報であるため、各シンボルのビット長のみを格納する必要があります。これはシンボルあたりのビット数が比較的少ないため、かなりコンパクトにする必要があります。その情報をさらに圧縮することもできます(Aki Suihkonenの回答を参照)。
当然、コードのビット長は基本的にツリーの深さと同じなので、これはおおよそあなたが求めていることだと思います。重要な部分は、長さを考慮して、正規のコードを作成する方法を知ることです。これは、ツリーをトラバースすることによって生成されるコードと必ずしも同じではありません。これからツリーを再生成することもできますが、必ずしも最初に作成したツリーである必要はありません。ただし、通常、最初にコードの長さを決定する以外にツリーは必要ありません。
正規コードを生成するためのアルゴリズムはかなり単純です。
- コードを生成するすべてのシンボルを取得し、最初にコード長(最初に最短)でソートし、次にシンボル自体でソートします。
- 長さゼロのコードから始めます。
- 次のシンボルが現在コードにあるよりも多くのビットを必要とする場合は、正しい長さになるまでコードの右側(最下位ビット)にゼロを追加します。
- コードを現在のシンボルに関連付け、コードをインクリメントします。
- すべてのシンボルを生成するまで、(3)にループバックします。
文字列「バナナ」を取ります。明らかに、「b」、「a」、および「n」の3つの記号が使用されており、それぞれ1、3、および2のカウントがあります。
したがって、ツリーは次のようになります。
*
/ \
* a
/ \
bn
素朴に、それはコードを与える可能性があります:
a = 1
b = 00
n = 01
ただし、代わりに、正規のコード生成への入力としてビット長を使用する場合は、次のようになります。
a = 0
b = 10
n = 11
コードは異なりますが、明らかに同じ長さの圧縮出力が生成されます。さらに、コードを再現するために必要なのはコード長のみです。
したがって、シーケンスを保存するだけで済みます。
0 ... 1 2 0 ... 20..。
ここで、「...」は簡単に圧縮できる繰り返しを表し、値はすべて非常に小さくなります(おそらく、それぞれ4ビットのみです。シンボルはまったく保存されないことに注意してください)。この表現は非常にコンパクトになります。
本当にツリー自体を格納する必要がある場合、1つの手法は、ツリーをトラバースして1ビットを格納し、ノードが内部かリーフかを示し、リーフノードの場合はシンボルコードを格納することです。これは、すべてのシンボルを含まないツリーではかなりコンパクトであり、かなり完全なツリーでもそれほど悪くはありません。これの最悪の場合のサイズは、すべてのシンボルの合計サイズに加えて、ノードを持つことができる限り多くの単一ビットになります。標準の8ビットバイトストリームの場合、320バイトになります(コードの場合は256バイト、ツリー構造自体の場合は511ビット)。
この方法は、ルートノードから開始し、ノードごとに次のようにします。
- ノードが親の場合は、0を出力してから、左から右の子を出力します。
- ノードがリーフの場合は、1を出力してからシンボルを出力します
再構築するには、同様の再帰的な手順を実行しますが、明らかにデータを読み取り、必要に応じて、子を再帰的に作成するか、シンボルを読み込むかを選択します。
上記の例では、ツリーのビットストリームは次のようになります。
0、0、1、'b'、1、'n'、1、'a'
これは、ツリーの場合は5ビット、シンボルの場合は3バイトであり、4バイトのストレージに切り上げられます。ただし、シンボルを追加すると急速に大きくなりますが、コード長を格納することはできません。