在0.01%到10%之间的位将被设置(随机,无模式)。
考虑到缺乏结构和相对较小的大小,这些如何进行压缩?
(我的第一个想法是存储已设置位之间的距离。每个距离需要13位,但在最坏情况下,10%的占用需要
13 * 816/8
= 1326
字节,这并没有改进。)这是为超低带宽通信而设计的,因此每个字节都很重要。
13 * 816/8
= 1326
字节,这并没有改进。)如果集合中只有很少的元素,那么你无法比使用数组更好。例如:[3, 1, 4711, 8140]。在这种情况下,数据被编码为数组。
如果几乎所有元素都在集合中,那么你可以跟踪不在集合中的元素。例如:[8190,17,42]。
如果集合中大约一半的元素,则几乎无法找到更好的方法,除了位图。因此,你会得到[4000,{bitmap}]。这是唯一一种数据长度比严格未压缩的情况更长的情况。
如果集合中的元素比“很少”多,但比“大约一半”少,我发现另一种策略。将集合中可能的值的位分成两半。假设我们有2^16(更容易描述,应该适用于2^13)个可能的值。这些值被分为256个范围,每个范围有256个可能的值。然后,我们有一个包含256个字节的数组,每个字节描述了每个范围中有多少个值(所以字节0告诉我们有多少个元素是[0,255],字节1给出[256,511]等等)。紧随其后的是每个范围中值模256的数组。这里的技巧是,虽然集合中的每个元素编码为数组(策略1)都将是2个字节,但在此方案中,每个元素仅为1个字节+ 256个静态字节,用于元素计数。这意味着,一旦我们的集合中有超过256个元素,通过从策略1切换到4,我们可以通过节省空间来实现。
策略4可以被优化(如果你的数据是随机的,那么可能没有意义,但我的数据有时会有更多的模式,所以对我有用)。由于在先前的编码中每个元素仍需要8位,因此一旦元素的子数组超过32个元素(256字节),我们就可以将其存储为位图。这也是在策略4/5和3之间切换策略的好断点。如果该策略中的所有数组都只是位图,则应该使用策略3(它比这更复杂,但是策略之间的断点可以预先计算得非常精确,以便每次都选择最可能有效的策略)。
我只是大致尝试了保存集合中数字之间的差异。快速实验表明,它们并不比我上面提到的策略更有效,具有不可预测的退化情况,但最重要的是,我使用的应用程序真的很喜欢不必反序列化其数据,直接从磁盘(mmap)中使用原始数据。