我试图压缩一系列非负数,其中:
每个号码只出现一次(表示共有2 ^ N个号码)
N = 4的例子:
[14,1,8,2,12,6,0,10,4,15,5,7,15,9,3,11]
因此通常每个数字将花费4位,对于16个数字,我们将不得不使用16x4 = 64位来存储它们。
目前我刚考虑压缩它们如下:
因此压缩数据大小为:
Z = 8 * 4 + 4 * 3 + 2 * 2 + 1 * 1 + 1 * 0 = 49 bits
压缩率约为76%,这非常好(我认为)。
但是对于较大的N值,该比率似乎会降低(对于N = 2048,该比率仅为91%)
所以我想听听你有关更好压缩的建议。
谢谢。
答案 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
接近N
,id
趋于无穷大。
鉴于这种压缩率的绝对限制,任何合理有效的方法都值得去;对于小到N = 15的值,不可能做到比90%好。
答案 2 :(得分:2)
目前您使用的是N * 2 ^ N位。
基本上你拥有的是数字的排列,每个排列都是唯一的,对于排列,你可以计算一个唯一的标识符。既然有(2 ^ N)!排列,你只需要ceil(log2((2 ^ N)!))位。例如,这是45位。