存储压缩集的最佳方式

时间:2017-06-13 01:55:34

标签: c arrays algorithm set compression

正如标题所说,我正在寻找在内存中存储集合的最佳方式。我只对字节集(从0255的整数数组感兴趣,其中顺序并不重要)。编码/解码不需要快速。唯一必要的是集合应该尽可能少的内存。

我想出的第一个方法是为每个集合分配256位(32个字节)的数组,位置n的位告诉n是否存在n在集合中或不在集合中。这种方法的问题是因为它需要相同数量的内存,即使该集合大多是空的(只有很少的元素)。

我尝试的第二种方法是将集合存储为常规数组。因此,如果一个集合包含n + 1个元素,那么它将需要存储32个字节。第一个字节表示元素的数量,其他字节表示元素。但是,正如我们所知,顺序排列并不重要,所以强烈地告诉我必须有一种方法来推动这一点。

我的第三次尝试是枚举所有可能的集合,并且只存储set的索引(整数在所有可能的字节集列表中表示其索引)。但是,事实证明它与第一种方法完全相同。基本上,我仍然需要n个字节来存储任何集合,所以它不是很有用。

我做的第四次尝试是基于我的第二种方法。我注意到包含n + 1元素的集合当然需要k字节(如果我使用第二种方法)。但是,例如,如果元素k出现在集合中(实际上在数组中,因为在我的第二次尝试中我将集合存储为数组),则它不能再次出现。基本上,如果k - 1再次出现,那么它必须意味着不同的东西(也许[3, 3, 5, 7])。所以,我做了一些优化,我注意到如果我对每个下一个元素进行不同的编码,我可以保存一些字节(例如,3被解释为{3, 4, 5}元素的元素,其元素为[3, 3, 5, 6](每个下一个元素都会被其索引减少而{3, 4, 2}被解释为3(注意46已经存在,因此2减少了4 {1}}它变为4,但3存在并且2存在,因此它必须是1))。但是这种方法怎么能真正节省字节呢?我试验并意识到我可以在数组中对元素进行排序,以便在某些情况下避免使用高位编码元素,因此每个元素保存n / 16位,大约为n / 2 * 1 / 8保存的字节数(128)。

我做的第五种方法类似于我的第二种方法,但它不同地解释了数字元素。如果元素的数量小于128,则它通常会读取内存中以下数组的所有元素。但是,如果元素的数量大于128,则它会创建一个完整集,然后只从内存中的以下数组中删除元素。平均而言,节省了大量字节,但它仍远离最佳状态。

我的最后一次尝试(第六次尝试)是枚举一些集合(例如创建一个集合列表,其中包含:完整集合,仅设置偶数,仅设置奇数,设置元素小于128,设置元素大于128等)然后使用该列表中的元素和基本集合操作(​​并集,交集等)来重建原始集合。对于我们在列表中使用的每个基本集,它将需要几个字节,并且它将需要几个位用于并集或交集操作,当然还需要一个字节来表示序列的长度。它非常依赖于基本集列表中应该硬编码的元素数量,但似乎很难预先创建并正确选择该列表中的元素。无论如何,有些东西告诉我这不是一个非常聪明的方法。

但是,帽子实际上是最优化的方式吗?有些东西告诉我,我的第四次尝试并不是那么糟糕,但我们可以做得更好吗?我使用的集合具有随机数量的元素,因此每个集合平均128个元素,因此我正在寻找一种方法来为每个集合分配16个位({{1}}个字节)。到目前为止我做的最好的是使用我的第四种方法,这种方法远离我的目标。

再说一次,速度并不重要。编码/解码可能极其缓慢,唯一重要的是集合需要尽可能少的内存。当我在内存中说"" 我的意思是在内存中编码(压缩)。此外,我感兴趣的是尽可能少的位(不仅仅是字节),因为我想在我的硬盘上存储数十亿个压缩集,因此计算每个集所需的平均位数非常重要,所以我知道有多少资源可以达到我想要达到的目的。

P.S。如果你想要一些代码(但我真的不明白你为什么会这样做),我可以在这里发布我在C中为所有这些方法制作的解决方案。无论如何,我不是要求代码或技术细节如何在特定的编程语言中实现它,我只是要求压缩集合的方法/算法。

提前谢谢。

2 个答案:

答案 0 :(得分:2)

您的第一种方法(和第三种方法,相当)已经是最佳方法。它无法改进。

您正在使用2个 256 可能的数字集。根据鸽子原理,您需要2个 256 数字来识别它们,并且您需要256位来表示这些数字。任何识别使用少于256位的集合的方法都会留下至少一对(可能是很多对)集合共享相同标识符的集合。

答案 1 :(得分:0)

有2 ^ 256个可能的字节集。

如果所有集合都具有相同的可能性,那么您可以做的最好的事情是使用常量256位(32字节)来指示您拥有的2 ^ 256种可能性中的哪一种。

你似乎不喜欢这个想法,因为你认为只有少数元素的集合应该占用更少的比特。但如果它们不可能比其他任何一组发生,那么这将不是最佳的。

如果更少的元素集更可能,那么使用常量32字节最优,但最佳编码取决于可能集的精确概率分布,你没有给。信息论的相关概念是“熵”:https://en.wikipedia.org/wiki/Entropy_(information_theory)

简洁地说,在最佳编码中,所有2 ^ 256个可能的集合所需的平均位数将是Sum_of_allPᵢ* -log 2(Pᵢ),其中每个Pᵢ是必须编码特定集合的概率(所有Pᵢ必须总和为1)

如果元素的数量是您认为应该影响编码大小的唯一的,那么你不能对这样的事情做错太多:

1)使用1个字节写出集合中的元素数量。有257种可能的设置大小,但是0和256个元素都可以使用0。

2)在具有该长度的所有集合的枚举中写出集合的索引。 (如果你写了0,那么你需要1位来指示空集或全集)。如果已知该组具有N个元素,则该数字所需的位数将为 log 2(256!/(N!*(256-N)!)