Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Language agnostic 有效集交点-确定交点是否大于k_Language Agnostic_Data Structures_Set_Intersection - Fatal编程技术网

Language agnostic 有效集交点-确定交点是否大于k

Language agnostic 有效集交点-确定交点是否大于k,language-agnostic,data-structures,set,intersection,Language Agnostic,Data Structures,Set,Intersection,我面临一个问题,我必须计算集合中所有对之间的交点。没有一个集合小于一个小常数k,我只关心两个集合的交集是否大于k-1元素。我不需要实际的交叉点,也不需要确切的大小,只需要它是否大于k-1。是否有一些聪明的预处理技巧或一套整洁的求交算法可以用来加快速度 更多有助于回答问题的信息: 这些集合表示大型无向稀疏图中的最大团。集合的数量可以是数万或更多,但大多数集合可能很小 集合已排序,每个集合的成员按递增顺序排列。实际上,它们是经过排序的列表——我通过这种方式从底层库中接收它们,以便进行最大的派系搜索

我面临一个问题,我必须计算集合中所有对之间的交点。没有一个集合小于一个小常数k,我只关心两个集合的交集是否大于k-1元素。我不需要实际的交叉点,也不需要确切的大小,只需要它是否大于k-1。是否有一些聪明的预处理技巧或一套整洁的求交算法可以用来加快速度

更多有助于回答问题的信息:

  • 这些集合表示大型无向稀疏图中的最大团。集合的数量可以是数万或更多,但大多数集合可能很小
  • 集合已排序,每个集合的成员按递增顺序排列。实际上,它们是经过排序的列表——我通过这种方式从底层库中接收它们,以便进行最大的派系搜索
  • 对于集合中元素的分布(即它们是否处于紧密的簇中)一无所知
  • 大多数集合交叉点可能是空的,因此理想的解决方案是一个聪明的数据结构,它可以帮助我减少集合交叉点的数量

一种可能的优化,每套中包含的值范围越小,优化效果越好:

  • 创建一个所有集合的列表,按它们的第k个最大元素排序(这很容易找到,因为您已经有了每个集合及其元素的顺序)。把这个列表称为L
  • 对于任意两个集合A和B,如果A中的第k个最大元素小于B中的最小元素,则它们的交集中不能有多达k个元素
  • 因此,对于每个集合,依次计算其与L的相关部分中的集合的交点
您可以使用相同的事实提前退出计算任意两个集合的交集-如果其中一个集合中只剩下n-1个元素可供比较,并且交集到目前为止最多包含k-n个元素,则停止。上面的过程就是这个规则一次应用于L中的所有集合,n=k,此时我们正在查看集合B的最小元素和A的第k个最大元素。

考虑A,其中大小为k的所有集合作为键,以及集合中包含键作为子集的所有集合列表的相应值。给定此映射,您不需要执行任何交集测试:对于每个键,列表中的所有集合对都将具有大小至少为k的交集。这种方法可以多次生成同一对集合,因此需要进行检查

映射很容易计算。对于集合中的每个集合,计算所有size-k子集,并将原始集合附加到该键集的列表中。但这真的更快吗?通常不会。此方法的性能将取决于集合中集合大小的分布和k的值。如果集合中有d个不同的元素,则可以有多达d个choose k键,这些键可能非常大

但是,基本思想可用于减少交叉口的数量。与其使用大小为k的集合,不如使用大小为q的较小集合作为键。这些值也是将键作为子集的所有集合的列表。现在,测试列表中的每对集合的交点。因此,当q=1时,只测试至少有一个共同元素的集合对;当q=2时,只测试至少有两个共同元素的集合对,依此类推。我认为,q的最佳值取决于集合大小的分布


对于所讨论的集合,一个好的选择可能是q=2。然后,关键点就是图形的边,为映射提供了一个可预测的大小。由于大多数集合都是不相交的,因此q=2应该消除很多比较,而不会产生太多额外的开销

以下策略应该非常有效。我已经在很多场合使用过这种方法的变体来交叉升序序列

首先,我假设您有某种优先级队列可用(如果没有,滚动您自己的堆非常容易)。和快速键/值查找(btree、hash等)

话虽如此,这里是一个算法的伪代码,它应该可以非常有效地完成您想要的任务

# Initial setup
sets = array of all sets
intersection_count = key/value lookup with keys = (set_pos, set_pos) and values are counts.
p_queue = priority queue whose elements are (set[0], 0, set_pos), organized by set[0]

# helper function
def process_intersections(current_sets):
    for all pairs of current_sets:
        if pair in intersection_count:
            intersection_count[pair] += 1
        else:
            intersection_count[pair] = 1

# Find all intersections
current_sets = []
last_element = first element of first thing in p_queue
while p_queue is not empty:
    (element, ind, set_pos) = get top element from p_queue
    if element != last_element:
        process_intersections(current_sets)
        last_element = element
        current_sets = []
    current_sets.append(set_pos)
    ind += 1
    if ind < len(sets[set_pos]):
        add (sets[set_pos][ind], ind, set_pos) to p_queue
# Don't forget the last one!
process_intersections(current_sets)

final answer = []
for (pair, count) in intersection_count.iteritems():
    if k-1 < count:
        final_answer.append(pair)
#初始设置
集合=所有集合的数组
交叉点计数=键/值查找,键=(设置位置,设置位置),值为计数。
p_queue=优先级队列,其元素为(集合[0],0,集合位置),按集合[0]组织
#辅助函数
def过程_交叉点(当前_集合):
对于所有当前_集对:
如果交叉点中有一对\u计数:
交叉点计数[对]+=1
其他:
交叉点计数[对]=1
#找到所有交叉点
当前_集=[]
last_element=p_队列中第一件事的第一个元素
当p_队列不为空时:
(element,ind,set_pos)=从p_队列中获取顶部元素
如果元素!=最后一个元素:
处理交叉点(当前集合)
最后一个元素=元素
当前_集=[]
当前设置追加(设置位置)
ind+=1
如果ind

运行时间为
O(总和(集合大小)*log(集合数量)+计数(一个点在一对集合中的次数)
。特别要注意的是,如果两个集合没有交集,您就永远不会尝试将它们相交。

如果您使用预测子集作为预限定符,该怎么办。预排序,但使用子集交集作为阈值条件。如果子集交集>n%,则完成交集,否则放弃