12

List<List<Boolean>>を持っていて、それを可能な限りコンパクトな方法でバイナリ形式にエンコードしたいとしましょう。

読み取りまたは書き込みのパフォーマンスは気にしません。最小限のスペースを使いたいだけです。また、例は Java ですが、Java システムに限定されません。各「リスト」の長さは無制限です。したがって、各リストの長さをエンコードするソリューションは、それ自体で可変長データ型をエンコードする必要があります。

この問題に関連するのは、可変長整数のエンコードです。List<Boolean>それぞれを可変長と考えることができますunsigned integer

質問をよく読んでください。Java システムに限定されません。

編集

多くの回答が圧縮について話している理由がわかりません。私はそれ自体を圧縮しようとはしていませんが、ビットのランダムなシーケンスをエンコードしているだけです。ただし、各ビット シーケンスの長さは異なり、順序を維持する必要があります。

この質問は別の方法で考えることができます。ランダムな符号なし整数 (無制限) の任意のリストのリストがあるとします。このリストをバイナリ ファイルにどのようにエンコードしますか?

リサーチ

私はいくつかの読書をしましたが、私が本当に探しているのはユニバーサルコードであることがわかりました

結果

論文で説明されているElias Omega Codingのバリアントを使用します。正の整数の新しい再帰的ユニバーサル コード

小さい整数の表現が小さいほど、大きい整数とのトレードオフになることがわかりました。最初の整数の「大きな」表現を持つユニバーサルコードを選択するだけで、任意の大きな整数をエンコードする必要がある場合に、長期的には多くのスペースを節約できます。

4

16 に答える 16

9

次のようなビットシーケンスをエンコードすることを考えています:

head  | value
------+------------------
00001 | 0110100111000011

Head可変長です。その終わりは、最初の 1 の発生によってマークされます。頭の中のゼロの数を数えます。valueフィールドの長さは になります2 ^ zeroes。値の長さがわかっているため、このエンコードを繰り返すことができます。のサイズは でheadあるlog valueため、エンコードされた値のサイズが大きくなるにつれて、オーバーヘッドは 0% に収束します。

補遺

値の長さをさらに微調整したい場合は、値の正確な長さを格納する別のフィールドを追加できます。長さフィールドの長さは、頭の長さによって決定できます。これは 9 ビットの例です。

head  | length | value
------+--------+-----------
00001 | 1001   | 011011001
于 2010-02-02T00:21:49.583 に答える
7

私はJavaについてあまり知らないので、私の解決策は一般的でなければならないと思います:)

1.リストを圧縮します

ブール値は非効率的であるため、それぞれList<Boolean>をに圧縮する必要がありますList<Byte>。簡単です。一度に8つ取得するだけです。

最後の「バイト」は不完全である可能性があるため、もちろんエンコードされたビット数を保存する必要があります。

2.要素のリストをシリアル化する

続行するには2つの方法があります。リストの項目数をエンコードするか、パターンを使用して終了をマークするかです。アイテムの数をエンコードすることをお勧めします。パターンアプローチではエスケープが必要で、不気味です。さらに、パックされたビットではより困難です。

長さをエンコードするには、可変スキームを使用できます。つまり、長さをエンコードするために必要なバイト数は、すでに使用した長さに比例する必要があります。最初のバイトにプレフィックスを使用することで、長さ自体をエンコードするために使用されるバイト数を指定できます。

0... .... > this byte encodes the number of items (7 bits of effective)
10.. .... / .... .... > 2 bytes
110. .... / .... .... / .... .... > 3 bytes

スペース効率が非常に高く、デコードはバイト全体で行われるため、それほど難しくはありません。これはUTF8スキームと非常によく似ていると言えます:)

3.再帰的に適用します

List< List< Boolean > >[Length Item ... Item]それぞれItemがそれ自体である場所になりますList<Boolean>

4.ジップ

zlibJava、またはまたはのような他のライブラリで利用できるライブラリdeflateがあると思いますlcw。それをあなたのバッファに渡し、それがかかる時間に関係なく、あなたができるだけ多くの圧縮を望むことを正確にすることを確認してください。

表現に繰り返しパターンがある場合(表示されていないパターンでも)、それを圧縮できるはずです。しかし、それをばかげて信用しないでください。「圧縮された」形式が「圧縮されていない」形式よりも軽いことを確認してください。常にそうであるとは限りません。

5.例

リストの端を追跡するのはスペースを消費することに気づいたところ:)

// Tricky here, we indicate how many bits are used, but they are packed into bytes ;)
List<Boolean> list = [false,false,true,true,false,false,true,true]
encode(list) == [0x08, 0x33] // [00001000, 00110011]  (2 bytes)

// Easier: the length actually indicates the number of elements
List<List<Boolean>> super = [list,list]
encode(super) == [0x02, 0x08, 0x33, 0x08, 0x33] // [00000010, ...] (5 bytes)

6.スペース消費

ブール値がありList<Boolean>nそれをエンコードするために消費されるスペースは次のとおりです。

booleans = ceil( n / 8 )

ビット数(n)をエンコードするには、次のものが必要です。

length = 1   for 0    <= n < 2^7   ~ 128
length = 2   for 2^7  <= n < 2^14  ~ 16384
length = 3   for 2^14 <= n < 2^21  ~ 2097152
...
length = ceil( log(n) / 7 )  # for n != 0 ;)

したがって、リストを完全にエンコードするには、次のようにします。

bytes =
 if n == 0: 1
 else     : ceil( log(n) / 7 ) + ceil( n / 8 )

7.小さなリスト

ただし、1つのコーナーケースがあります。それは、スペクトルの下限(つまり、ほとんど空のリスト)です。

についてはn == 1bytesに評価されますが2、これは実際には無駄に思えるかもしれません。ただし、圧縮が開始されるとどうなるかを推測しようとはしません。

さらに詰めたいと思うかもしれません。バイト全体を保持するという考えを放棄すれば可能です...

  1. 長さのエンコーディングを(バイト全体で)そのままにしますが、を「パディング」しないでくださいList<Boolean>。1要素リストは0000 0001 x(9ビット)になります
  2. 長さのエンコーディングも「パック」してみてください

2番目のポイントはもっと難しく、事実上2倍の長さのエンコーディングになります。

  1. 長さをエンコードするビット数を示します
  2. 実際にこれらのビットの長さをエンコードします

例えば:

0  -> 0 0
1  -> 0 1
2  -> 10 10
3  -> 10 11
4  -> 110 100
5  -> 110 101
8  -> 1110 1000
16 -> 11110 10000 (=> 1 byte and 2 bits)

非常に小さなリストではかなりうまく機能しますが、すぐに縮退します。

# Original scheme
length = ceil( ( log(n) / 7)

# New scheme
length = 2 * ceil( log(n) )

限界点?8

うん、あなたはそれを正しく読んでいます、それは8要素未満のリストにのみ良いです...そして「ビット」によってのみ良いです。

n         -> bits spared
[0,1]     ->  6
[2,3]     ->  4
[4,7]     ->  2
[8,15]    ->  0    # Turn point
[16,31]   -> -2
[32,63]   -> -4
[64,127]  -> -6
[128,255] ->  0    # Interesting eh ? That's the whole byte effect!

そしてもちろん、圧縮が開始されると、それは実際には問題にならない可能性があります。

のアルゴリズムに感謝するかもしれませんがrecursive、実際のスペース消費量の数値を計算するか、実際のテストセットにアーカイブを適用して実際にテストすることをお勧めします。

8.再帰的/変数コーディング

私は興味を持って答えを読み、彼がエリアスオメガコーディングTheDonに提出したリンクを読みました。

それらは、理論的な領域では、正しい答えです。残念ながら、それらは非常に実用的ではありません。主な問題は、それらが非常に興味深い漸近的な振る舞いをすることですが、実際にギガバイト相当のデータをエンコードする必要があるのはいつですか?まれに。

職場でのメモリ使用量に関する最近の調査では、ほとんどのコンテナが1ダース(または数十)のアイテムに使用されていることが示唆されています。非常にまれなケースでのみ、1000に到達します。もちろん、特定の問題については、実際に自分のデータを調べて値の分布を確認するのが最善の方法ですが、経験から、データはローエンドにあるため、スペクトルのハイエンドだけに集中することはできません。 。

TheDonのアルゴリズムの例。私がリストを持っていると言う[0,1,0,1,0,1,0,1]

len('01010101') = 8 -> 1000
len('1000')     = 4 -> 100
len('100')      = 3 -> 11
len('11')       = 2 -> 10

encode('01010101') = '10' '0' '11' '0' '100' '0' '1000' '1' '01010101'

len(encode('01010101')) = 2 + 1 + 2 + 1 + 3 + 1 + 4 + 1 + 8 = 23

再帰を停止するためのさまざまな「しきい値」を備えた小さなテーブルを作成しましょう。のさまざまな範囲のオーバーヘッドのビット数を表しますn

threshold     2    3    4    5      My proposal
-----------------------------------------------
[0,3]    ->   3    4    5    6           8
[4,7]    ->   10   4    5    6           8
[8,15]   ->   15   9    5    6           8
[16,31]  ->   16   10   5    6           8
[32,63]  ->   17   11   12   6           8
[64,127] ->   18   12   13   14          8
[128,255]->   19   13   14   15         16

公平を期すために、私はローエンドに集中しました、そして私の提案はこのタスクに適しています。しかし、それはそれほど明確ではないことを強調したかったのです。特に、に近いため1log関数はほぼ線形であり、再帰はその魅力を失います。しきい値は非常に役立ち3、良い候補のようです...

に関してはElias omega coding、それはさらに悪いです。ウィキペディアの記事から:

17 -> '10 100 10001 0'

それだけです、11ビットの大騒ぎ。

道徳:手元のデータを考慮せずにエンコード方式を選択することはできません。

だから、あなたList<Boolean>が数百の長さを持っていない限り、わざわざ私の小さな提案に固執しないでください。

于 2010-02-01T18:47:37.590 に答える
4

可変長整数を使用して、読み取るビット数をエンコードします。MSB は、次のバイトも整数の一部であるかどうかを示します。例えば:

11000101 10010110 00100000

実際には次のことを意味します。

   10001 01001011 00100000

整数が2回続くので。

これらの可変長整数は、読み取るビット数を示します。そして、最初に別の可変長 int があり、読み取るビットセットがいくつあるかを示します。

そこから、圧縮を使用したくないと仮定すると、サイズに関して最適化する唯一の方法は、状況に適応させることです。より大きなビット セットを頻繁に使用する場合は、たとえば、可変長整数エンコーディングにバイトではなく short 整数を使用して、エンコーディング自体で無駄になるビットを減らすことができます。


編集必要なものをすべて一度に達成する完璧な方法は存在しないと思います。何もないところから情報を作成することはできません。可変長の整数が必要な場合は、明らかに整数の長さもエンコードする必要があります。スペースと情報の間には必然的にトレードオフがありますが、スペースを節約するために切り取ることができない最小限の情報もあります。要因が異なる速度で成長するシステムは、完全に拡張されることはありません。対数曲線に直線を当てはめようとするようなものです。そんなことはできません。(さらに、それはまさにあなたがここでやろうとしていることです。)

可変長整数の長さを整数の外でエンコードし、同時に無制限のサイズの可変整数を取得することはできません。これは、長さ自体を可変長にする必要があり、どのアルゴリズムを選択しても、それは常識のようです。私には、2 つ以上の可変長整数ではなく、1 つの可変長整数の方がよいと思います。

だからここに私の他の考えがあります:整数の「ヘッダー」で、そこから可変長整数が必要とする各バイトに1を書き込みます。最初の 0 は、「ヘッダー」の終わりと整数自体の始まりを示します。

私が与えた 2 つの方法で与えられた整数を格納するために必要なビット数を決定するために正確な方程式を把握しようとしていますが、私の対数はさびているので、プロットして後でこのメッセージを編集して結果を含めます。 .


編集2 ここに式があります:

  • 解決策 1、エンコード ビットごとに 7 ビット (一度に 1 バイトずつ):
    y = 8 * ceil(log(x) / (7 * log(2)))
  • 解決策 1、エンコーディング ビットあたり 3 ビット (一度に 1 ニブル):
    y = 4 * ceil(log(x) / (3 * log(2)))
  • 解決策 2、エンコーディング ビットごとに 1 バイトとセパレータ:
    y = 9 * ceil(log(x) / (8 * log(2))) + 1
  • 解決策 2、エンコーディング ビットごとに 1 つのニブルとセパレータ:
    y = 5 * ceil(log(x) / (4 * log(2))) + 1

完全な解決策はないため、時間をかけてそれらをプロットすることをお勧めします (対数線形座標系で表示するのが最適です) 。私の意見では、最初のソリューションが最も安定した結果をもたらします。

于 2010-02-01T23:27:47.400 に答える
3

「可能な限り最もコンパクトな方法」では、ある程度の圧縮が必要になると思いますが、静的なシンボルごとの周波数を持つアルファベットで最適に機能すると思うので、ハフマンコーディングは適切ではない可能性があります。

算術符号化を確認してください。ビットで動作し、動的な入力確率に適応できます。また、入力としてシングルビットを期待しているように見えるBSDライセンスのJavaライブラリがあります。

最大の圧縮率を得るには、各内部リスト(接頭辞が長さ)を連結して、ロット全体でコーディングアルゴリズムを再度実行できると思います。

于 2010-01-29T19:48:20.910 に答える
3

任意のビット セットのエンコードと、他の形式のデータの圧縮/エンコードとの違いがわかりません。エンコードするビットに緩い制限を課すだけであることに注意してください。つまり、それらはビットのリストのリストです。この小さな制限により、このビットのリストは単なるデータ、任意のデータになり、それが「通常の」圧縮アルゴリズムで圧縮されます。

もちろん、ほとんどの圧縮アルゴリズムは、LZxx ファミリの圧縮プログラムのように、入力が将来 (または過去) に何らかの方法で繰り返されるか、シンボルの特定の頻度分布を持っているという前提で機能します。

前提条件と圧縮アルゴリズムの仕組みを考えると、次のことをお勧めします。

  1. 可能な限り少ないバイト数を使用して各リストのビットをパックし、バイトをビットフィールドとして使用し、長さをエンコードします。
  2. 結果のバイトストリームに対してハフマン、算術、LZxx などを試してください。

これが非常に明白で最も簡単な方法であり、ビットのシーケンスには既知のパターンがないため、これは機能しないと主張できます。しかし、実際には、これがどのシナリオでもできる最善の方法です。

ただし、データから何かを知っている場合、またはそれらのリストにある種のパターンを発生させる何らかの変換を知っている場合を除きます。たとえば、JPEG エンコーディングでの DCT 係数のコーディングを考えてみましょう。これらの係数 (対角線およびジグザグ) をリストする方法は、変換のさまざまな係数の出力のパターンを優先するように作成されています。このようにして、従来の圧縮を結果のデータに適用できます。より圧縮しやすい方法 (より構造を示す方法) でそれらを再配置できるビットのリストの一部を知っている場合は、圧縮が得られます。

于 2010-02-01T18:38:05.770 に答える
3

最悪の場合、真にランダムなビットのセットをよりコンパクトな形式にエンコードすることはできないのではないかと、こっそりと疑っています。どのような種類の RLE も、平均的で最良のケースではうまく機能しますが、間違った入力だけでセットを膨張させます。あらゆる種類の定期的またはコンテンツ固有の近似では、データが失われます。

他のポスターの1人が述べたように、データセットをよりコンパクトな形式で表現するには、データセットについて何かを知る必要があります。また、よりコンパクトに表現できる予測可能な形式にするために、ある程度の損失を受け入れる必要があります。 .

私の考えでは、これは無限の情報とゼロ損失の制約を伴う情報理論の問題です。情報を別の方法で表現することはできず、より簡単に表現できるものとして近似することもできません。したがって、少なくとも情報と同じだけのスペースが必要であり、それ以下ではありません。

http://en.wikipedia.org/wiki/Information_theory

ハードウェアを操作して、メディア上の個別の範囲の値をエンコードして、さらにいくつかの「ビットごとのビット」を引き出すことができると思います(多重化を考えてください)。ただし、それをエンコードして読むのにより多くの時間を費やすことになります。

実際には、データを複数の方法で複数回エンコードする「ジグル」効果をいつでも試すことができます (オーディオ、ビデオ、3D、定期的、順次、キーベース、差分などとして解釈してみてください...) 複数のページサイズで。そして最高のものを選びます。最高の合理的な圧縮が行われることがほぼ保証され、最悪の場合でも元のデータ セットよりも悪くはなりません。

ただし、それで理論的に最善の結果が得られるかどうかはわかりません。

于 2010-02-01T23:51:51.680 に答える
2

理論上の限界

これは、圧縮しようとしているデータについて詳しく知らなければ答えるのが難しい質問です。あなたの質問に対する答えは、ドメインによって異なる場合があります。

たとえば、ロスレス圧縮に関するウィキペディアの記事の制限セクションから:

ロスレス データ圧縮アルゴリズムは、すべての入力データ セットの圧縮を保証できません。言い換えると、どの (ロスレス) データ圧縮アルゴリズムでも、アルゴリズムによって処理されたときに小さくならない入力データ セットが存在します。これは、カウント引数を使用して初等数学で簡単に証明されます。...

基本的に、考えられるすべての入力データを無損失で圧縮することは理論的に不可能であるため、質問に効果的に回答することさえできません。

実用的な妥協

Huffman、DEFLATE、7Z、または ZIP のような既製の圧縮アルゴリズムを使用して、ビットを可変長バイト配列 (またはリスト、ベクトル、または Java または任意の言語で呼び出されるもの) としてエンコードします。もちろん、ビットを読み戻すには少し圧縮解除が必要になる場合がありますが、これはバックグラウンドで実行できます。データがパックバイト配列に内部的に格納されているにもかかわらず、内部実装メソッドを非表示にして、特定の範囲のインデックスでブール値のリストまたは配列を返すクラスを作成できます。特定のインデックスでブール値を更新することは問題になる可能性がありますが、決して不可能ではありません。

于 2010-02-01T18:39:23.677 に答える
1

List-of-Lists-of-Ints-Encoding:

  • リストの先頭に来たら、ASCII '[' のビットを書き留めます。次に、リストに進みます。

  • 任意の 2 進数に到達したら、数値の 10 進数表現に対応するビットを ASCII で書き留めます。たとえば、100 の場合、0x31 0x30 0x30 と書きます。次に、ASCII ',' に対応するビットを書き込みます。

  • リストの最後に来たら、']' のビットを書き留めます。次に、ASCII ',' を書き込みます。

このエンコーディングは、無制限の整数の任意の長さのリストの任意の深さのネストをエンコードします。このエンコーディングが十分にコンパクトでない場合は、gzip でフォローアップして、ASCII ビット コーディングの冗長性を排除します。

于 2010-02-02T00:37:22.187 に答える
0

この質問には、ある種の誘導感があります。次の関数が必要です:(ブールリストリスト)->(ブールリスト)逆関数(ブールリスト)->(ブールリストリスト)が同じ元の構造を生成し、エンコードされたブールリストの長さが最小であり、入力構造に制限を課します。この質問は非常に抽象的であるため、これらのリストは気が遠くなるほど大きくなる可能性があると思います。おそらく10 ^ 50、または10 ^ 2000、あるいは10^0のように非常に小さい可能性があります。また、多数のリストが存在する可能性があります。これも10 ^ 50または1だけです。したがって、アルゴリズムはこれらの大きく異なる入力に適応する必要があります。

各リストの長さを(ブールリスト)としてエンコードし、次のシーケンスが別の(現在は大きい)長か実際のビットストリームかを示すためにブールを1つ追加できると考えています。

encode2d(list1d :: Bs)= encode1d(length(list1d)、true)@ list1d @ encode2d(Bs)
    encode2d(nil)= nil

encode1d(1、nextIsValue)= true :: nextIsValue::[]とします。
    encode1d(len、nextIsValue)=
               bitList = toBoolList(len)@ [nextIsValue] in
               encode1d(length(bitList)、false)@ bitList

decode2d(bits)=
               let(list1d、rest)= decode1d(bits、1)in
               list1d :: decode2d(rest)

decode1d(bits、n)=
               長さ=fromBoolList(take(n、bits))in
               nextIsValue::ビット'=skip(n、bits)in
               nextIsValueの場合はビット'elsedecode1d(bits'、length)
想定されるライブラリ関数
-------------------------

toBoolList:int-> bool list
   この関数は整数を取り、ブールリスト表現を生成します
   ビットの。入力「0」を除いて、先行ゼロはすべて削除されます

fromBoolList:bool list-> int
   toBoolListの逆

take:int *a'リスト->a'リスト
   リストの最初のカウント要素を返します

スキップ:int *a'リスト->a'リスト
   最初のカウント要素を削除した後、リストの残りを返します

オーバーヘッドは、個々のブールリストごとです。空のリストの場合、オーバーヘッドは2つの追加のリスト要素です。10 ^ 2000ブールの場合、オーバーヘッドは6645 + 14 + 5 + 4 + 3 + 2=6673追加のリスト要素になります。

于 2010-02-02T04:58:23.963 に答える
0

私が正しく理解している場合、データ構造は ( 1 2 ( 33483 7 ) 373404 9 ( 337652222 37333788 ) ) です。

次のようにフォーマットします。

byte 255 - escape code
byte 254 - begin block
byte 253 - list separator
byte 252 - end block

したがって、次のようになります。

 struct {
    int nmem; /* Won't overflow -- out of memory first */
    int kind; /* 0 = number, 1 = recurse */
    void *data; /* points to array of bytes for kind 0, array of bigdat for kind 1 */
 } bigdat;

 int serialize(FILE *f, struct bigdat *op) {
   int i;
   if (op->kind) {
      unsigned char *num = (char *)op->data;
      for (i = 0; i < op->nmem; i++) {
         if (num[i] >= 252)
            fputs(255, f);
         fputs(num[i], f);
      }
   } else {
      struct bigdat *blocks = (struct bigdat *)op->data
      fputs(254, f);
      for (i = 0; i < op->nmem; i++) {
          if (i) fputs(253, f);
          serialize(f, blocks[i]);
      }
      fputs(252, f);
 }

任意の符号なし整数のセットのセットについて、バイト値が高いほど発生が少ないという数値の桁数分布に関する法則があるため、最後に特別なコードを配置します。

それぞれの前に長さをエンコードしないと、使用するスペースがはるかに少なくなりますが、逆シリアル化が困難になります。

于 2010-02-02T05:20:42.547 に答える
0

各 List を BitSet に変換してから、BitSet をシリアル化できます。

于 2010-01-29T19:10:27.090 に答える
0

List-of-List-of-Ints-binary:

Start traversing the input list
For each sublist:
    Output 0xFF 0xFE
    For each item in the sublist:
        Output the item as a stream of bits, LSB first.
          If the pattern 0xFF appears anywhere in the stream,
          replace it with 0xFF 0xFD in the output.
        Output 0xFF 0xFC

デコード:

If the stream has ended then end any previous list and end reading.
Read bits from input stream. If pattern 0xFF is encountered, read the next 8 bits.
   If they are 0xFE, end any previous list and begin a new one.
   If they are 0xFD, assume that the value 0xFF has been read (discard the 0xFD)
   If they are 0xFC, end any current integer at the bit before the pattern, and begin reading a new one at the bit after the 0xFC.
   Otherwise indicate error. 
于 2010-02-02T01:38:28.893 に答える
0

ご指摘のとおり、1 ビット以上のスペースを使用してブール値を格納する理由はありません。これを、各行がその行のビット数をコーディングする整数で始まるなどの基本的な構造と組み合わせると、行の各エントリが 1 ビットである任意のサイズの 2D テーブルを格納できます。

しかし、これでは十分ではありません。任意の 1 と 0 の文字列はかなりランダムに見え、圧縮アルゴリズムはデータのランダム性が増すにつれて機能しなくなります。そのため、Burrows-Wheeler ブロック ソートのようなプロセスを使用して、繰り返される「単語」または「」の量を大幅に増やすことをお勧めします。ブロック」をデータに追加します。これが完了すると、単純なハフマン コードまたは Lempel-Ziv アルゴリズムでファイルを適切に圧縮できるようになります。

上記の方法を符号なし整数に対して機能させるには、デルタ コードを使用して整数を圧縮し、次にブロックの並べ替えと圧縮を実行します (情報検索投稿リストの標準的な方法)。

于 2010-02-01T18:58:57.343 に答える
0

まず、これらのブール値をまとめて、1 バイトに 8 つになるようにします。C++ の標準ビットセットは、この目的のために設計されました。可能であれば、ベクトルの代わりにネイティブに使用する必要があります。

その後、理論上は保存時に圧縮してサイズをさらに小さくすることができます。あなたの背中が本当に壁にぶつかっていない限り、私はこれに反対することをお勧めします.

それはあなたのデータに大きく依存するので、私は理論的に言います。一部のアルゴリズムは特定の種類のデータに対して他のアルゴリズムよりもうまく機能するため、データについて何も知らなければ、これ以上これ以上言うことはできません. 実際、単純な情報理論によると、圧縮アルゴリズムによっては、最初よりも多くのスペースを占める出力が生成される場合があります。

ビットセットがかなりまばらである (多くの 0 や多くの 1 ではない) か、または縞模様 (同じ値が長時間続く) である場合、圧縮によって大きな利益が得られる可能性があります。他のほとんどすべての状況では、手間をかける価値はありません。そのような状況でもそうではないかもしれません。追加するコードは、デバッグして維持する必要があることに注意してください。

于 2010-02-01T18:48:23.987 に答える
0

@zneakの答え(私を打ち負かします)ですが、特にいくつかの長さが可能性が高い場合は、ハフマンでエンコードされた整数を使用してください。

自己完結型にするために:リストの数をハフマンでエンコードされた整数としてエンコードし、次にリストごとに、そのビット長をハフマンでエンコードされた整数としてエンコードします。各リストのビットは、間に無駄なビットがなくても続きます。

リストの順序が問題にならない場合は、長さでソートすると必要なスペースが減り、後続の各リストの長さの増分だけをエンコードする必要があります。

于 2010-02-01T23:52:11.587 に答える
0

質問を正しく理解していれば、ビットはランダムであり、個別にランダムな長さのリストのランダムな長さのリストがあります。バイトを扱うものは何もないので、これをビット ストリームとして説明します。ファイルには実際にはバイトが含まれているため、各バイトにパック 8 ビットを配置し、最後のバイトの 0..7 ビットを未使用のままにしておく必要があります。

ブール値を格納する最も効率的な方法は、そのままです。それらを単純な配列としてビットストリームにダンプするだけです。

ビットストリームの先頭で、配列の長さをエンコードする必要があります。それには多くの方法があり、アレイに最適な方法を選択することで数ビットを節約できます。これには、一般的に使用される小さな値が最短のシーケンスになるように、固定コードブックでハフマン コーディングを使用することをお勧めします。リストが非常に長い場合、長い形式でエンコードされるサイズについてはあまり気にしないでしょう。

コードブック (したがってハフマン コード) がどうなるかについての正確な答えは、予想されるリストの長さに関する詳細情報なしでは得られません。

すべての内部リストが同じサイズの場合 (つまり、2D 配列がある場合)、もちろん、必要なのは 2 次元だけです。

逆シリアル化: 長さをデコードして構造体を割り当て、ビットを 1 つずつ読み取り、構造体に順番に割り当てます。

于 2010-02-02T00:28:49.007 に答える