如何压缩一系列非重复数字大小的N位?

时间:2015-05-08 17:42:15

标签: c++ algorithm compression

我试图压缩一系列非负数,其中:

  • 每个数字的取值范围为0到2 ^ N-1
  • 每个号码只出现一次(表示共有2 ^ N个号码)

    N = 4的例子:

    [14,1,8,2,12,6,0,10,4,15,5,7,15,9,3,11]

因此通常每个数字将花费4位,对于16个数字,我们将不得不使用16x4 = 64位来存储它们。

目前我刚考虑压缩它们如下:

  • 对于前8个数字 - >使用4位来存储它们。
  • 接下来的4个数字--->只有3位/每个
  • 接下来的两个数字--->只有2位/每个
  • 接下来的1个数字--->只有1位。
  • 对于最后一个,实际上并不需要存储(显然,如果我们知道所有其他15个数字,我们应该知道最后一个数字是什么)

因此压缩数据大小为:

Z = 8 * 4 + 4 * 3 + 2 * 2 + 1 * 1 + 1 * 0 = 49 bits 

压缩率约为76%,这非常好(我认为)。

但是对于较大的N值,该比率似乎会降低(对于N = 2048,该比率仅为91%)

所以我想听听你有关更好压缩的建议。

谢谢。

3 个答案:

答案 0 :(得分:3)

正如评论中所指出的,最佳编码 - 如果所有排列都是同等可能的 - 是用排列枚举中的索引替换整个排列。因为有 n !可能的排列,索引需要log 2 n !比特,因此每个元素使用log 2 n 位的原始编码的压缩比为(log n !)/( n log n )。

使用Stirling's approximation,我们可以将其重写为( n log n - n + O(log n ))/( n log n ),即1 - 1 /(log n )+ O(1 / < em> n )随着 n 的增长,它明显渐近逼近1。因此,对于较大的 n ,压缩比将不可避免地降低。

除非并非所有排列都是同等可能的(并且您有关于概率分布的信息),否则无法实现更好的压缩。

答案 1 :(得分:2)

对于此特定问题,最有效的编码方法是在factorial number system中查看[0 .. 2^N-1]的数字排列,并为该排列存储Lehmer code

这给出了ceil(log2((2^N)!))位的要求。对于N = 4,这使用45位(70.3%);对于N = 11(2 ^ N = 2048),19581位(86.9%)。

压缩比随着N的增加而恶化;使用简单逼近log x! >= (x log x) - x + 1,我们得到log2((2^N)!) / (N 2^N) 1 - ((2^N - 1)/(2^N))*(1 / (N * log(2)))的最小值,1接近Nid趋于无穷大。

鉴于这种压缩率的绝对限制,任何合理有效的方法都值得去;对于小到N = 15的值,不可能做到比90%好。

答案 2 :(得分:2)

目前您使用的是N * 2 ^ N位。

基本上你拥有的是数字的排列,每个排列都是唯一的,对于排列,你可以计算一个唯一的标识符。既然有(2 ^ N)!排列,你只需要ceil(log2((2 ^ N)!))位。例如,这是45位。