整数列表的子集计算

时间:2013-01-02 14:14:16

标签: algorithm sorting set bloom-filter

我目前正在实施一种算法,其中一个特定步骤要求我按以下方式计算子集。

想象一下,我有整数的集合(可能是数百万)。每个集合可能包含大约1000个元素:

Set1: [1, 3, 7]
Set2: [1, 5, 8, 10]
Set3: [1, 3, 11, 14, 15]
...,
Set1000000: [1, 7, 10, 19]

想象一下特定的输入集:

InputSet: [1, 7]

我现在想快速计算出这个InputSet是一个子集。在这种特殊情况下,它应该返回Set1和Set1000000。

现在,暴力迫使花费太多时间。我也可以通过Map / Reduce进行并行化,但我正在寻找更智能的解决方案。此外,在某种程度上,它应该是内存有效的。我已经通过使用BloomFilters来快速消除输入集永远不会成为子集的集合来优化计算。

我错过了任何智能技术?

谢谢!

4 个答案:

答案 0 :(得分:2)

嗯 - 看起来瓶颈是套数,所以不是通过迭代所有这些来找到一个集合,而是通过从元素映射到包含它们的所有集合来增强性能,并返回包含所有集合的集合。你搜索过的元素。

这与在inverted index字段中搜索information retrieval时在AND查询中执行的操作非常类似。

在您的示例中,您将拥有:

1 -> [set1, set2, set3, ..., set1000000]
3 -> [set1, set3]
5 -> [set2]
7 -> [set1, set7]
8 -> [set2]
...

修改
在IR中的倒排索引中,为了节省空间,我们有时使用 d-gaps - 这意味着我们存储文档之间的偏移而不是实际数字。例如,[2,5,10]将成为[2,3,5]。这样做并使用delta encoding来表示数字在空间方面往往会有很大帮助。
(当然还有一个缺点:你需要阅读整个列表以查找是否有特定的集/文档,并且不能使用二进制搜索,但它有时是值得的,特别是如果它是将索引拟合到RAM中的区别与否。)

答案 1 :(得分:0)

如何存储包含每个数字的集合列表?

1 -- 1, 2, 3, 1000000
3 -- 1, 3
5 -- 2
etc. 

答案 2 :(得分:0)

  1. 从最大数量(7)的输入集开始搜索 消除其他子集(将返回Set1和Set1000000)。

  2. 在剩余的集合中搜索其他输入元素(1)。

答案 3 :(得分:0)

扩展amit的解决方案,而不是存储实际数字,您可以只存储间隔及其相关集。

例如,使用间隔大小为5:

 (1-5): [1,2,3,1000000]
 (6-10): [2,1000000]
 (11-15): [3]
 (16-20): [1000000]

在(1,7)的情况下,你应该考虑间隔(1-5)和(5-10)(可以简单地通过知道间隔的大小来确定)。相交这些范围可以得到[2,1000000]。对集合的二进制搜索表明,两个集合中确实存在(1,7)。

虽然您需要检查每组的最小值和最大值,以便更好地了解间隔大小应该是什么。例如,如果最小值和最大值从1到100万,则5可能是一个糟糕的选择。

您应该保留它,以便可以使用二进制搜索来检查值,因此子集范围应该类似于(min + max)/ N,其中2N是需要的最大值数在每组中搜索二进制。例如,“set 3是否包含5到10之间的任何值?”这是通过找到最接近5(3)和10(11)的值来完成的,在这种情况下,不是。您必须遍历每个集合并对二进制搜索进行可能在集合中的间隔值。这意味着当设置仅达到10时,确保您不会搜索100。

您也可以存储范围(最小和最大)。但是,问题在于我怀疑你的号码将被聚集,因此没有提供太多用途。虽然如上所述,它可能对确定如何设置间隔很有用。

选择使用范围太大而且构建数据结构需要很长时间(1000 *百万* log(N))仍然很麻烦。太小了,你将开始遇到太空问题。该范围的理想大小可能确保与每个范围相关的集合数量大致相等,同时还确保范围总数不会太高。

编辑: 一个好处是,您实际上不需要存储所有间隔,只需要存储所需的间隔。但是,如果您有太多未使用的间隔,则可能明智的做法是增加间隔并拆分当前间隔以确保搜索速度很快。如果游行时间不是主要问题,则尤其如此。