用于查看许多不同数组是否是另一个数组的子集的算法?

时间:2016-12-14 21:50:04

标签: algorithm performance data-structures language-agnostic subset

假设我有一个~20-100个整数的数组,例如[0, 1, 2, 3, 4, 5, 6, 7, 8, 9](实际上数字更像[106511349 , 173316561, ...],所有非负64位整数都在2 ^ 63之间,但是出于演示目的,让我们使用这些。)

许多(~50,000)较小的数组,通常为1-20个术语,以匹配或不匹配:

1=[2, 3, 8, 20]
2=[2, 3, NOT 8]
3=[2, 8, NOT 16]
4=[2, 8, NOT 16] (there will be duplicates with different list IDs)

我需要找到哪些是正在测试的数组的子集。匹配列表必须具有所有正匹配,而没有负匹配。所以对于这个小例子,我需要找回像[3, 4]这样的东西。列表1无法匹配,因为它需要20,而列表2无法匹配,因为它没有8.在这些情况下,使用高位/使数字为负可以很容易地表示NOT。

我需要每秒快速执行10,000次。小阵列是固定的" (它们不经常更改,比如每隔几秒钟一次),而每个要扫描的数据项完成大数组(每秒10,000个不同的大数组)。

这已经成为一个瓶颈,所以我正在研究如何优化它。

我不确定最佳数据结构或表示方式。一种解决方案是扭转它,看看我们甚至需要考虑哪些小清单:

2=[1, 2, 3, 4]
3=[1, 2]
8=[1, 2, 3, 4]
16=[3, 4]
20=[1]

然后我们建立一个要检查的列表列表,并对这些列表进行完整的子集匹配。但是,某些术语(通常是更频繁的术语)最终会出现在许多列表中,因此这里的实际胜利并不多。

我想知道是否有人知道更好的算法来解决这类问题?

4 个答案:

答案 0 :(得分:0)

你可以尝试用较小的数组创建一个树,因为它们的变化频率较低,这样每个子树都会尝试将剩下的小数组的数量减半。

例如,对较小数组中的数字进行频率分析。找到最接近一半较小数组的数字。在树中进行第一次检查。在你的例子中,它是'3',因为它出现在一半的小数组中。现在,这是树中的头节点。现在将包含3的所有小列表放到左子树中,将所有其他列表放到右子树中。现在递归地在每个子树上重复此过程。然后当一个大数组进来时,反向索引它,然后遍历子树以获取列表。

答案 1 :(得分:0)

您没有说明哪些数组已排序 - 如果有的话。

由于您的数据不是很大,我会使用哈希映射来存储源集的条目(具有~20-100整数的条目)。这基本上可以让你测试O(1)中是否存在整数。

然后,假设50,000(数组)* 20(每个术语)* 8(每个字节的字节数)= 8兆字节+(哈希映射开销),对于大多数系统来说似乎不大,我会使用另一个哈希映射存储经过测试的数组。这样您就不必重新测试重复项。

答案 2 :(得分:0)

我意识到从CS的角度来看这可能不太令人满意,但是如果你做了大量不会相互影响的小任务,你可能会考虑将它们并行化(多线程)。每秒10,000个任务,比较每个任务中的不同阵列,应该符合要求;你没有提供你正在做的其他事情的任何细节(例如,所有这些阵列来自哪里),但可以想象多线程可以通过一个很大的因素来提高你的吞吐量。

答案 3 :(得分:0)

首先,做你的建议;从输入整数到它所存在的过滤器数组的ID创建一个hashmap。这可以让你说“输入#27在这400个过滤器中”,然后将这400个放入一个有序集合中。然后,您必须为每个排序的集合执行交集。

可选:从每个输入整数到其过滤器集合中的频率制作第二个散列映射。当输入进入时,使用第二个hashmap对其进行排序。然后使用最不常见的输入整数并从中开始,这样您在每个步骤上的总体工作就会减少。同时计算“非”情况的频率,因此您在每一步中基本上都能获得最大的收益。

最后:这很容易变成并行编程问题;如果它在一台机器上不够快,似乎你可以很容易地把更多的机器放在它上面,如果它返回的东西足够有用。