我有一个小范围[0,k)
的n个整数序列,并且所有整数具有相同的频率f
(因此序列的大小为n=f∗k
)。我现在要做的是在提供随机访问(什么是第i个整数)时压缩此序列。实现随机访问的时间不必是O(1)。我更感兴趣的是以更高的随机访问时间为代价来实现高压缩。
我没有尝试使用霍夫曼编码,因为它根据频率分配代码(我的所有频率都是相同的)。也许我错过了一些针对这种特殊情况的简单编码。
任何帮助或指示都将不胜感激。
提前致谢。
PS:已经在cs.stackexchange中询问了,但是在这里也要求更好的报道,对不起。
答案 0 :(得分:2)
如果所有整数具有相同的频率,那么最佳压缩的公平近似将是每整数ceil(log2(k))
位。您可以在固定的时间内访问这些位数组。
如果k
非常小(如3),则上述方法可能会浪费相当多的空间。但是,您可以将固定数量的小整数组合成一个基数 - k
数字,它可以更有效地拟合到固定数量的位中(您也可以方便地将结果拟合到标准大小的数字中)字)。在任何情况下,您也可以在固定的时间内访问此编码。
如果整数不具有相同的频率,则最佳压缩可能会从输入的不同部分产生可变比特率,因此简单的数组访问将不起作用。在这种情况下,良好的随机访问性能需要一个索引结构:将压缩数据分解为方便大小的块,每个块可以按顺序解压缩,但这一次受到块大小的限制。
如果每个数字的频率完全相同,你可以利用这个来节省一些空间 - 但这可能还不够值得。
范围n
中[0,k)
个随机数的熵为n log2(k)
,每个数字为log2(k)
位;这是在没有利用确切频率的情况下编码数字所需的位数。
f
复制每个k
元素(其中n=f*k
)的可区分排列的熵是:
log2( n!/(f!)^k ) = log2(n!) - k * log2(f!)
应用斯特林的近似值(仅当n
和f
很大时才适用),产生:
~ n log2(n) - n log2(e) - k ( f log2(f) - f log2(e) )
= n log2(n) - n log2(e) - n log2(f) + n log2(e)
= n ( log2(n) - log2(f) )
= n log2(n/f)
= n log2(k)
这意味着,如果n
很大且k
很小,则您不会通过利用输入的确切频率获得大量空间。
上述斯特林近似值的总误差为O(log2(n) + k log2(f))
,每个编码的数字为O(log2(n)/n + log2(f)/f)
。这意味着如果您的k
太大而f
很小(即每个不同的数字只有少量副本),那么您可以通过巧妙的编码节省一些空间。但是,该问题指出k
实际上很小。
答案 1 :(得分:1)
如果您计算出可能的不同组合的数量并获取其日志基数2,您可以找到最佳的压缩,我认为在您的情况下它不会那么好。频率为16的16个数字可能的消息数为16!和Excel告诉我2的基数为16!是44.25,而将它们存储为4位代码只需要64位。 (你想要的每种类型都有多种http://mathworld.wolfram.com/MultinomialCoefficient.html)
我认为将随机访问混合到此会有问题,因为您拥有的唯一信息是每种类型的元素都有固定数量 - 在整个序列中。对于整个序列来说,这并不是很多信息,并且它几乎没有关于序列的前半部分,因为你可能在上半部分中有更多的数字而在下半部分则更少。