効率的な方法で保存ハフマンツリー
-
09-09-2019 - |
質問
皆様にお伝えしたくて書き込み、ハフマン符号化/復号ツールおよび宿の効率的な方法でのハフマンツ作成された店舗の出力ファイルです。
現在は、バージョンが異なっているといいでしょうか?
- この読み込み、全体のファイルをメモリ文字の文字とともに、周波数のテーブルに書きします。このようにするために出力するツリーに一度、このように効率性がないとのことで大きな懸念されるもの以外の場合は入力ファイルは小さい。
- その他の方法に使用するだけではつまらないのでチャンクのデータ、約64キロバイトのサイズの周波数解析と、ツリー、エンコードします。ただし、この場合前に各チャンクが必要になると出力は私の周波数のツリーのデコーダでの再構築ツリーを正しくデコードの符号化されたファイルです。そこで、効率的な入場所から保存したいとされたほどのスペースは可能です。
自分で検索していきたいと思い見つかりませんで良い方法を格納するツリーとして設置スペースにできるしたいと思ってStackOverflowの地域で、ティーチング-アシスタント!
解決
からだき,誠にありがとうござい実行コードをビット-ワイス層の上のバイト主催のストリーム/ファイルを、自分なりの提言をしてます。
保管したりしないでください実際の周波数ではありませんが必要な復号化また、実際の樹木です。
うに各ノードの始まりのルート:
- が葉ノード:出力1ビット+N-bitの文字のバイト
- ない場合は葉ノード、0を出力ビットとしています。そしてエンコードの両方の子ノードを左初めて目に右)同じように
読みん:
- 読みます。1の場合は、読み取N-bitの文字/byte戻り、新しいノードでない子ども
- が少した0のデコード左右の子ノードと同様、新規ノードの周りにさせながら、子どもが価値
葉ノードは基本的にノードを持たない子どもたち。
このアプローチは、数の変化を計測することにより、正確なサイズの出力前に書いたりしていく場合の利益に十分に正当化します。この想定している辞書のキーと値のペアが含まれる各文字の出現頻度が高、周波数は、実際の発行数.
擬似コードの算出:
Tree-size = 10 * NUMBER_OF_CHARACTERS - 1
Encoded-size = Sum(for each char,freq in table: freq * len(PATH(char)))
木のサイズの計算の葉は、葉以外のノードを考慮が少ないインラインノードにより文字です。
SIZE_OF_ONE_CHARACTERするビット数、そのいいビット数の合計が私のアプローチツリー+エンコードされたデータを占める.
パス(c)は、機能テーブルが利回りのビットパスからのルートをこの文字のです。
ここで、C#のみ擬似コードでは一文字だけのシンプルなバイトになります。
void EncodeNode(Node node, BitWriter writer)
{
if (node.IsLeafNode)
{
writer.WriteBit(1);
writer.WriteByte(node.Value);
}
else
{
writer.WriteBit(0);
EncodeNode(node.LeftChild, writer);
EncodeNode(node.Right, writer);
}
}
お読みい:
Node ReadNode(BitReader reader)
{
if (reader.ReadBit() == 1)
{
return new Node(reader.ReadByte(), null, null);
}
else
{
Node leftChild = ReadNode(reader);
Node rightChild = ReadNode(reader);
return new Node(0, leftChild, rightChild);
}
}
例(簡体字、利用性等) ノードの実装:
public class Node
{
public Byte Value;
public Node LeftChild;
public Node RightChild;
public Node(Byte value, Node leftChild, Node rightChild)
{
Value = value;
LeftChild = leftChild;
RightChild = rightChild;
}
public Boolean IsLeafNode
{
get
{
return LeftChild == null;
}
}
}
こちらのサンプル出力から特定の一例です。
入力:AAAAAABCCCCCCDDEEEEE
周波数:
- A:6
- B:1
- C:6
- D:2
- E:5
各キャラクターには8ビットのサイズのツリーまで10 * 5 - 1 =49ビット.
ツリーは次のようになります:
20
----------
| 8
| -------
12 | 3
----- | -----
A C E B D
6 6 5 1 2
そのパスの各文字は、次のようになります(0は、1(右)
- A:00
- B:110
- C:01
- D:111
- E:10
での計算に出力サイズ:
- A:6発生*2ビット=12ビット
- B:1発生*3ビット=3ビット
- C:6発生*2ビット=12ビット
- D:2発生*3ビット=6ビット
- E:5発生*2ビット=10ビット
和の符号化されたバイトは12+3+12+6+10 = 43 ビット
追加することに49ビットのツリーからの出力は92ビット、12バイトまでとなります。を比較するための20*8バイトに必要なお店は元の文字数が20文字エンコードせずそのま保存8バイトまでとなります。
最終的な出力を含め、ツリーについては下記のとおりです。各文字のストリーム(A-E)は、符号化された8ビットは0と1だけのシングルビット.のスペースのストリームには個別のツリーからの符号化されたデータは、スペースの最終出力に出力します。
001A1C01E01B1D 0000000000001100101010101011111111010101010
の具体例をコメントAABCDEFを取得します:
入力:AABCDEF
周波数:
- A:2
- B:1
- C:1
- D:1
- E:1
- F:1
木:
7
-------------
| 4
| ---------
3 2 2
----- ----- -----
A B C D E F
2 1 1 1 1 1
パス:
- A:00
- B:01
- C:100
- D:101
- E:110
- F:111
木:001A1B001C1D01E1F=59ビット
データ:000001100101110111=18ビット
和:59+18=77ビット=バイト10
当初から7文字の下位8ビット=56てもオーバーヘッドなどのデータです。
他のヒント
までの制御の世代、すな標準的なツリー(同じように DEFLATE は、例えば、基本的にはこのルール作りの解決につ曖昧な状況をビルドする際のツリーが表示されます:そのようなDEFLATEございますのでご注意下さいが実際に店舗に長をコードしました。
それは、まった場合、ツリー/コードのLasse述:
- A:00
- B:110
- C:01
- D:111
- E:10
そのたれとして2,3,2,3,2
ことになる際に十分な情報を再生し、ハフマンテーブルを想定しいと同じ文字セット--と言う、ASCII.ことはせんでしたが、少し足を延ばせばスキップ文字--いリストコード長さはそれぞれの場合でも、このゼロになります。)
きもを入れの制限は少し長さ(例えば、7つのビット単位)、お店それぞれの番号を使用shortバイナリ文字列です。で2,3,2,3,2な010 011 010 011 010--う2バイトにまとめられます。
取得したい場合、 本当に 狂ういうDEFLATEは、他のハフマンテーブルの長さのソースコードなので、店舗、コード長さです。特に彼らに追加のコードサイトのサービスをゼロにN回連続"の短縮のためのものです。
RFCのための柔軟なものであれば、既に馴染みのハフマン符号化: http://www.ietf.org/rfc/rfc1951.txt
枝が0の葉は、その「形」を取得する最初のツリーの深トラバース1.されている。
e.g. the shape for this tree
0 - 0 - 1 (A)
| \- 1 (E)
\
0 - 1 (C)
\- 0 - 1 (B)
\- 1 (D)
would be 001101011
同じ深さの一次AECBD(読むときあなたは木の形状から期待するどのように多くの文字を知っているだろう)内の文字のためのビットでそれに従ってください。その後、出力メッセージのコード。あなたは、あなたは、出力のために文字に分けることができますビットの長いシリーズを持っています。
あなたはそれをチャンクしている場合は、は、あなたが次のチャックのツリーを格納すると、直前のチャンクのための木を再利用するほど効率的であることをテストし、ちょうどから木を再利用する指標として「1」である木の形状を持つことができます以前のチャンクます。
ツリーは一般的に作成したから周波数のテーブルにバイトになります。いるテーブルをバイトが自分をソートする周波数の作成のツリーができます。このコースを想定しているビルのツリーを代表するシングルバイトは大きいブロックとなります。
更新:指摘しているようにj_random_hackerにコメントは、実際にはできないこ必要な周波数値です。その組み合わせ、"バブル"上向きにして構築します。 このページ つのツリーの周波数。ボーナスパーツとしても救うことの回答から削除されているも保の木:
最も簡単な方法で出力ハフマンツリーそのものは、根底に、ダンプ初の左側の右側となります。各ノードで出力を0に、各葉まで出力1に続いてNビットを表す値です。
より良いアプローチ
ツリーます:
7
-------------
| 4
| ---------
3 2 2
----- ----- -----
A B C D E F
2 1 1 1 1 1 : frequencies
2 2 3 3 3 3 : tree depth (encoding bits)
今だけ、このテーブルを導出ます:
depth number of codes
----- ---------------
2 2 [A B]
3 4 [C D E F]
あなただけの、すなわちエンコーディングビット数を計算し、ツリーの深さを維持し、同じバイナリツリーを使用する必要はありません。だから、この別個のベクターに代えて相対インデックスを使用し、ツリーの深さによって順序付けられた非圧縮の値のベクトル[B C D E F]を維持します。今、各深さのために整列ビットパターンを再作成
depth number of codes
----- ---------------
2 2 [00x 01x]
3 4 [100 101 110 111]
あなたがすぐに参照することは各行の最初のビットパターンが重要であるということです。あなたは、次のルックアップテーブルを取得します:
first pattern depth first index
------------- ----- -----------
000 2 0
100 3 2
このLUTは、(あなたのハフマン符号は、32ビットの長さにすることができたとしても、それだけで32行が含まれます)非常に小さいサイズを持ち、実際に最初のパターンは常にnullであるバイナリを実行するとき、あなたはそれを完全に無視することができますその中のパターンの検索(ここでは1つだけのパターンは、ビット深度が2または3であるかどうかを知るために比較する必要があり、関連するデータをベクトルに格納されている最初のインデックスを取得します)。この例ではあなたが最大で31個の値の探索空間で入力パターンの高速なバイナリ検索を実行する必要があります、つまり5整数の最大値を比較します。これらの31のルーチンは、すべてのループを避けるために、31本のコードに最適化され、ときbrowing整数のバイナリ検索ツリーの状態を管理することが可能と比較します。 すべてのこのテーブルは、(LUTは単に32ビットより長くないハフマンコードの31行[最大必要があり、他の2列は、上記のほとんどの32行で充填する)小さな固定長に収まる。
ただしこれは、深さ列(および深さ1の最初の行)を暗示することにより、それを回避することができる:つまりLUTは、上記ビット深度値を格納する32ビットのサイズの31個のintそれぞれ、32バイトを必要とします
first pattern (depth) first index
------------- ------- -----------
(000) (1) (0)
000 (2) 0
100 (3) 2
000 (4) 6
000 (5) 6
... ... ...
000 (32) 6
だからあなたのLUTは、[000、100、000(30times)]が含まれています。これで検索するには、入力パターンのビット位置を見つけなければならない二つのパターンの間にある:それは、このLUTの次の位置にパターンよりも低くなければならないが、それでもより高いか、現在の位置(内のパターンに等しい両方の位置であれば同じパターンを含む、現在の行が一致しません、入力パターン)以下に収まります。 /その後/他のネストされたレベルが、それは32軒の支店を持ち、到達枝にはない、直接ビット深度を示している場合は、その後分割し、征服し、最大で5つのテストを使用しますよ(バイナリ検索が埋め込ま5で単一のコードが必要です格納する必要があります。あなたが最初のインデックスを戻すための第二のテーブルに単一の直接インデックス付きルックアップを実行し、あなたが復号された値のベクトルに付加的最終指標を導出する)
。 あなたは(第一列で検索)ルックアップテーブルの位置を取得したら、、すぐにベクトルに入力して、開始インデックスから取るようにビット数を持っています。あなたが得るビット深度は、最初のインデックスをsubstractingた後、基本的なbitmaskingにより、直接調整インデックス位置を導出するために使用することができます。
まとめ:リンクされたバイナリツリーを保存することはありませんし、あなただけの31パターンのテーブルに固定した位置にパターンを比較する5つのネストされたIFSを必要とするthelookupを実行するには、任意のループ、および開始を含む31個のint型のテーブルを必要としませんデコードされた値のベクトル内のオフセット(ネストされたのif / then /他のテストの最初の分岐では、ベクトルに開始オフセットが暗示され、それは常にゼロであり、それはまた、それが一致したとみなされます最も頻繁ブランチです最も頻繁に復号された値のためのものである最短コード)。