我有几百万套C的大集合。我的集合的元素来自大约2000个可能元素的世界。我需要知道,对于给定的集合,s,C中的集合与s的交集最大? (或者k在C中设置k个最大的交叉点)。我将依次针对不同的s进行许多这些查询。
我知道这样做的显而易见的方法是循环遍历C中的每个集合并计算交集并取最大值。是否有任何智能数据结构/编程技巧可以加快我的搜索速度?如果我能比O(C)更快地做到这一点会很棒。
编辑:大致的答案也没关系
答案 0 :(得分:3)
我认为没有一个聪明的数据结构可以帮助渐近性能。但这是一个完美的地图减少问题。 GPGPU会做得很好。对于2048个元素的Universe,作为位图的集合仅为256个字节。 400万只是一个千兆字节。即使是适度规范的Nvidia也有。例如。在CUDA编程,你将C复制到显卡RAM,将一块千兆字节映射到每个GPU核心进行搜索,然后减少核心以找到最终答案。这应该是几毫秒的量级。不够快?只需购买hotter hardware。
如果你按照这些方式重新表达你的问题,你可能会从这种编程的专家那里得到答案,我不是。
答案 1 :(得分:2)
一个简单的技巧是按大小按递减顺序对集合C列表进行排序,然后照常进行强力交叉测试。随着时间的推移,跟踪到目前为止最大交叉点的集合b。如果找到一个与查询集s的交集具有大小| s |的集合(或等效地,交叉点等于s - 使用这些测试中的哪一个更快),您可以立即停止并返回它,因为这是最好的答案。否则,如果C的下一个集合少于| b |元素,你可以立即停止并返回b。这很容易推广到找到前k个匹配。
答案 2 :(得分:1)
我没有看到任何方法在每个查询少于O(C)的情况下执行此操作,但我对如何最大限度地提高效率有一些想法。这个想法基本上是为每个元素构建一个查找表。如果某些元素很少见且有些元素很常见,那么您可以使用正面和负面查找表:
s[i] // your query, an array of size 2 thousand, true/false
sign[i] // whether the ith element is positive/negative lookup. +/- 1
sets[i] // a list of all the sets that the ith element belongs/(doesn't) to
query(s):
overlaps[i] // an array of size C, initialized to 0's
for i in len(s):
if s[i]:
for j in sets[i]:
overlaps[j] += sign[i]
return max_index(overlaps)
特别是如果你的许多元素具有广泛不同的概率(如你所说),这种方法可以节省你一些时间:非常罕见或非常常见的元素几乎可以立即处理。
要进一步优化:您可以对结构进行排序,以便首先处理最常见/最罕见的元素。完成第一个例如3/4,你可以做一个快速通过,看看最接近的匹配集是否远远超过下一组,没有必要继续,尽管这是否值得,取决于你的数据的细节' s分布。
另一个改进:使sets [i]成为两种可能结构之一:如果元素非常罕见或常见,则sets [i]只是第i个元素所在/不在的集合的列表。但是,假设第i个元素是集合的一半。然后,set [i]只是一个索引列表,只要集合数量的一半,循环遍历它并增加重叠是浪费的。 sign [i]有第三个值:如果sign [i] == 0,那么第i个元素相对接近50%的通用性(这可能只是意味着在5%到95%之间,或其他任何东西),而不是它出现的集合列表,它只是一个长度等于C的1和0的数组。然后你只需要将整个数组添加到更快的重叠中。
答案 3 :(得分:0)
将所有元素从百万集中放入Hashtable。键将是元素,值将是一组指向包含集的索引。
def shutdown():
global httpd
global please_die
print "Shutting down"
try:
please_die.wait() # how do you do?
httpd.shutdown() # Stop the serve_forever
httpd.server_close() # Close also the socket.
except Exception:
traceback.print_exc(file=sys.stdout)