计算两个大集合之间的集合差


14

我有两个大的整数集的AB。每组有大约一百万个条目,每个条目是一个正整数,最长为10位数字。

计算AB的最佳算法是什么BA?换句话说,如何有效地计算不在B中条目列表,反之亦然?代表这两组数据,使这些操作高效的最佳数据结构是什么?AB

我能想到的最好方法是将这两个集合存储为排序列表,并以线性方式将A每个元素与每个元素进行比较B。我们可以做得更好吗?


如果您愿意以其他方式存储它,则可能会获得更好的结果。
Realz Slaw

另外,如果您愿意将结果作为隐式数据结构获取;您可以建立一个查询两个集合的结构,以回答每个查询。
Realz Slaw

1
@ user917279的一大要点是:您通常可以权衡一下预处理/构造时间,查询时间和内存使用情况。您是否很少编辑结构,但查询很多?反过来呢?记忆是否值得关注?这些问题可以从实践的角度回答,并为“正确的”“理论的”结构的选择提供信息。
拉斐尔

1
@Raphael您是否建议通过使用更多的内存和/或花费更多的时间进行准备,而不是融合的持久性集(就复杂性而言)更好。如果您认为有可能,我很好奇。我没有将查找表作为此大小的输入集的选项。
smossen

1
@ user917279如果您考虑两个相同的巨大集合的示例,那么使用散列约束创建的任何数据结构都将支持O(1)中的相等性测试,因为相等的结构将在创建时合并并因此共享相同的内存位置。当两个结构几乎相等时,汇合的持久集也利用哈希约束。到目前为止,对于有序集,复杂度是最好的。
smossen 2013年

Answers:


9

如果您愿意将集合存储在专门的数据结构中,则可能会遇到一些有趣的复杂性。

I=O(min(|A|,|B|,|AΔB|))

然后,你可以做的一组操作一个Δ 中,每个Ø 登录|一个| + ||AB,AB,ABAΔB预计时间。因此,从本质上讲,您将获得两组的最小大小或对称差异的大小(以较小者为准)。如果对称差异较小,则此方法比线性方法好。即。如果他们有一个大的交叉点。实际上,对于您想要的两个集差运算,这实际上是输出敏感的,因为它们共同构成了对称差的大小。O(Ilog|A|+|B|I)

有关更多信息,请参见Olle Liljenzin(2013)的“ 合流持久性集和地图”


本文中的挖掘是有序搜索树。我不会将它们视为未排序的数据结构。
smossen

@smossen足够真实,我对此进行了编辑。
Realz Slaw

6

如果将集合表示为排序的链表,则线性扫描是我所知的最佳方法。运行时间为O(|A|+|B|)

请注意,您不需要成对比较每个元素和B的每个元素。这将导致运行时间为O | A | × | B |,这更糟。取而代之的是,要计算这两个集合的对称差异,可以使用类似于mergesort中的“ merge”操作的技术,并对其进行了适当的修改以忽略这两个集合共有的值。ABO(|A|×|B|)

更详细地讲,您可以构建如下所示的递归算法来计算,假设AB表示为链表,其值按排序顺序排列:ABAB

difference(A, B):
    if len(B)=0:
        return A # return the leftover list
    if len(A)=0:
        return B # return the leftover list
    if A[0] < B[0]:
        return [A[0]] + difference(A[1:], B)
    elsif A[0] = B[0]:
        return difference(A[1:], B[1:])  # omit the common element
    else:
        return [B[0]] + difference(A, B[1:])

我已经用伪Python表示了这一点。如果你不读的Python,A[0]是链表的头AA[1:]是列表的其余部分,并+表示名单的串联。出于效率方面的考虑,如果您使用的是Python,则可能不希望完全按上述方式实现它-例如,最好使用生成器,以避免建立许多临时列表-但我想以最简单的形式向您展示想法。此伪代码的目的只是为了说明算法,而不是提出具体的实现。

我认为,如果将集合表示为排序列表,并且希望将输出作为排序列表来提供,则不可能做得更好。从根本上讲,您必须查看B的每个元素。非正式的理由说明:如果您没有看过任何元素,就无法输出它,因此唯一可以忽略的元素就是您知道它在AB中都存在,但是如果您不看它的价值,怎么知道它的存在呢?ABAB


太棒了,如果消除了将集合存储为排序列表的约束,我们还有其他选择吗?
user917279 2013年

2

如果A和B的大小相等,不相交且交织(例如A中的奇数,B中的偶数),则线性时间中的项的成对比较可能是最佳的。

如果A和B包含正好在A或B之一或两者之中的项目块,则可以计算子线性时间中的集合差,并集和交集。例如,如果A和B的一项完全不同,则可以在O(log n)中计算出差异。

http://arxiv.org/abs/1301.3388


1
他说这些集合是有序的,这可能意味着它们被存储为列表,搜索树或其他内容。如果必须将数据存储为列表,那么当没有一种算法能比在线性时间内扫描列表更好的时候(他已经找到了一种算法),要求“计算AB的最佳算法”是没有意思的。
smossen 2013年

1
天哪,您链接了与我相同的文件(我,与您相同,相反)...下次给您的链接命名:D
Realz Slaw,2013年

@smossen太棒了,就我所知(?)而言,我将它们表示为排序列表,但也很欢迎其他建议。
user917279 2013年

2

nABab¯a,b


1010

1
R.,遗漏了要点。一个long可以存储32个元素或1个byte,8个元素。因此1M条目只能存储在约125K RAM中!根据问题的实现方式,该存储可以比其他表示有效得多...
vzn13年

因此,您需要超过12MB的OP感兴趣的集合。(当前)这会耗尽所有缓存,并且对于稀疏集合将是可怕的。特别是,创建一个空集将主导所有其他操作(对于稀疏集)。顺便说一下,Knuth在TAoCP中解决了这个问题。
拉斐尔

12MB??? 海报说他只有2套。张贴者未指定其布景的稀疏性/密度。我的答案中指出了这一点。您是否假设他有稀疏的场景?没有一个正确答案,指出该方法是一种替代选择,视情况而定。它在这种情况下并不罕见...
vzn13年

10101061010b1.15GB
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.