【问题标题】:Data structures for fast intersection operations?用于快速交叉路口操作的数据结构?
【发布时间】:2017-01-02 10:46:15
【问题描述】:

随机选择两个集合,两个集合都包含不同的键(一个键可能属于多个集合,一个集合永远不能包含重复的键)。

返回一个整数,表示属于两个集合的键数。

例如 intersect({1,2,3,4},{3,4,5}) 返回 2 。

我只需要十字路口的大小。我不需要确切知道十字路口有哪些钥匙。

是否有任何数据结构在不到 O(n) 时间内支持这种操作?

编辑:

读取数据确实需要 O(n) 时间,但 这不会导致您无法在 O(n) 时间内完成交集运算的结论 .

想象一下这个场景:

我有 N 个集合,每个包含 100 个键。我读了它们,那是 N*100 操作。现在我想知道女巫对集合有最大的交集,即 O(N²) 交集操作。所以我想降低交集操作的复杂性。我真的不关心读取和构造集合需要多少时间,最多 N*100,这与 O(N²) 的交集操作相比没什么。

请注意,您无法通过小于 O(N²) 的交集运算找到具有最大交集的集合对,我可以证明这一点。您必须完成所有相交操作。

(他的基本思想是,让我们想象一个完整的图,有 N 个顶点,每个顶点代表一个集合,Nx(N-1)/2 个边,每个代表连接对的交点。现在给每个边一个你想要的非负权重(代表交叉点大小),我总是可以构造 N 个集合满足那些 Nx(N-1)/2 个边缘权重。这证明了我的主张。)

【问题讨论】:

  • 这些集合是否有任何潜在有用的属性,例如,也许它们通常可以描述为几个范围的并集?
  • 获得更好复杂性的唯一方法是获得有关数据的更多信息。即便如此,我也不确定你能否达到 O(log n)。
  • 我在下面写了一个证明这样的算法不存在。
  • 无论你切片它,你都必须阅读所有的项目。没有比 O(n) 更好的解决方案。
  • @JimMischel 你的理由不充分。

标签: algorithm data-structures time-complexity intersection set-operations


【解决方案1】:

假设有一种算法允许在小于O(n) 的时间内检查交叉点的长度。现在让我们阅读部分输入。我们有两个选择: 我们已经阅读了整套和另一套的一部分,或者我们已经阅读了第一套的一部分和另一套的一部分。

选项 1):

反例 - 让我们采用这样的输入,即存在一个在集合 1 中读取但尚未从集合 2 中读取但在集合 2 中的元素 - 我们将收到不正确的结果。

选项 2):

反例 - 我们可以输入这样的存在元素,该元素存在于两组中,但至少有一组未被读取。我们收到不正确的结果。

好的,我们已经证明,当我们不读取整个输入时,没有这样的算法可以返回正确的结果。

让我们阅读整个输入 - n 数字。糟糕,复杂度为 O(n)

证明结束。

【讨论】:

  • 我为什么要再读一遍?我有两组正确构造为树或哈希图或其他东西。
  • 内存中已经有数据了。我只需要快速测试一下返回交集的大小。
  • 好吧,该结构可能是两个集合,并带有交叉值的附加字段。然后它将是O(1)。只需计算输入处的交点。输入何时结束?
  • 确实,在一般情况下,您不能有一种算法不能读取两组中的每个值,因为一个未读取的值可能会改变输出。如果我们对输入有特定的限制,那就不是真的了。 @iouvxz,你有这样的限制吗?
  • @Nelxost 想想这个场景,我有 N 个集合,每个包含 100 个键。我读了它们,那是 N*100 操作。现在我想知道女巫对集合有最大的交集,即 O(N²) 交集操作。所以我想降低交集操作的复杂性。我真的不关心读取和构建集合需要多少时间,最多 N*100,这与 O(N²) 交集操作相比没什么。
【解决方案2】:

我建议您看看两种可能的替代方案,它们在实践中效果特别好(尤其是在大型集合的情况下)。

1。 Bloom Filter 数据结构

布隆过滤器是一种节省空间(基于位数组)的概率数据结构,用于测试元素是否是集合的成员。假阳性匹配是可能的,但假阴性是不可能的。

在误报率和布隆过滤器的内存占用之间需要权衡。因此,可以针对不同的用例估计合适的布隆过滤器大小。

每个集合都可以与它自己的布隆过滤器相关联。 很容易得到Bloom Filter,对应不同集合的交集:所有对应不同Bloom Filter的位数组,可以通过按位AND操作组合。

拥有对应于交集的布隆过滤器,可以快速找到所有相交集中存在的项目。

除此之外,无需对整个集合进行实际迭代即可估计交集的基数: https://en.wikipedia.org/wiki/Bloom_filter#The_union_and_intersection_of_sets

2。 Skip list 数据结构

跳过列表是一种数据结构,它允许在有序的元素序列中进行快速搜索和交叉。通过维护子序列的链接层次结构,可以实现快速搜索和交叉,每个子序列跳过更少的元素。

简而言之,Skip List 与普通的 Linked List 数据结构非常相似,但是 Skip List 的每个节点都有几个指向项目的附加指针,它们位于更远的位置(指针,“跳过”这对列表的其他节点)。

因此,为了获得交集 - 需要维护所有正在相交的跳过列表中的指针。在跳过列表相交期间,指针跳过项目,这些项目并不存在于所有相交的跳过列表中。因此,通常相交操作的运行时复杂度比O(N) 更快。

Skip Lists 的交集算法在《Introduction to Information Retrieval》一书中进行了描述(作者:Christopher D. Manning、Prabhakar Raghavan、Hinrich Schütze): http://nlp.stanford.edu/IR-book/html/htmledition/faster-postings-list-intersection-via-skip-pointers-1.html

跳过列表在高性能、功能齐全的文本搜索引擎库中被积极使用:Apache Lucene(在倒排索引组件中使用跳过列表)。

这是关于在 Lucene 中使用跳过列表的另一个 Stackoverflow 问题:how lucene use skip list in inverted index?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-02
    • 2014-03-09
    • 1970-01-01
    • 1970-01-01
    • 2015-09-28
    • 2011-10-27
    • 1970-01-01
    相关资源
    最近更新 更多