Arrays 当有无限多个CPU时,比较两个数组的最佳方法是什么?
这是我在面试中遇到的问题。有两个排序的数组A和B。检查数组A中的每个元素是否出现在数组B中。假设有无限个CPU核。采访者建议算法应该在O(1)中运行。我只提出了一个O(log(n))解。有什么想法吗 另一方面,我的O(log(n))解决方案是将A中的一个元素分配给一个CPU核心,每个CPU使用二进制搜索来检查数组B中是否存在该元素。我记得采访者可能曾建议,在给定无限多个CPU的情况下,二进制搜索可以优化为O(1)。但我不确定。以防万一。以下是通用CRCW模型中的O(1),即,仅当写入相同的值时,才能进行并发写入。假设原始数组A有n个元素,而B有m个大小Arrays 当有无限多个CPU时,比较两个数组的最佳方法是什么?,arrays,algorithm,parallel-processing,Arrays,Algorithm,Parallel Processing,这是我在面试中遇到的问题。有两个排序的数组A和B。检查数组A中的每个元素是否出现在数组B中。假设有无限个CPU核。采访者建议算法应该在O(1)中运行。我只提出了一个O(log(n))解。有什么想法吗 另一方面,我的O(log(n))解决方案是将A中的一个元素分配给一个CPU核心,每个CPU使用二进制搜索来检查数组B中是否存在该元素。我记得采访者可能曾建议,在给定无限多个CPU的情况下,二进制搜索可以优化为O(1)。但我不确定。以防万一。以下是通用CRCW模型中的O(1),即,仅当写入相同的值时,
found = new bool[n]
parallel for i in 0..n-1:
found[i] = false
parallel for j in 0..m-1:
if A[i] == B[j]:
found[i] = true
result = true
parallel for i in 0..n-1:
if !found[i]:
result = false
print result ? "Yes": "No"
当然,我不完全确定这个模型有多实用。实际上,您可能没有并发写入。在具有独占写入的CREW模型中,您可以在O(logn)时间内计算AND和OR聚合,我认为相应的下限也存在
向面试官询问他感兴趣的平行模型的细节可能是个好主意。让每个核心从a中选取一个元素,从B中选取一对相邻元素。对每个可能的组合使用不同的核心。每个核心将比较它们的三个元素。如果A中的元素介于B中的两个元素之间(且两者都不相等),则A中的一个元素不会出现在B中
这缺少一些明显的优化。例如,a1000不需要与b1和b2进行比较,但与无限机器相比,谁在乎呢。为了补充Niklas B的非常好的答案,我补充说,对于O(1)解决方案,我怀疑在最坏的情况下,即使使用排序阵列,也不能使用小于Ω(MN)的内核 如果所有元素在两个数组中都出现一次(并且隐式地M=N),则可以在“面对”元素之间并行执行N个比较,即使用Θ(N)核 但是,当允许重复时,相等的元素可能会出现移位,移位可能会增大到Ω(M+N),并且事先不知道。要尝试所有元素的所有可能移位,您需要执行Ω(MN)比较。让A有总A元素,B有总B元素(我假设这些元素可能会重复) 我们需要总计((a*b)+1)个内核:我们要检查b中a的每个元素。因此,我们需要为a的每个元素总计b个处理器,因此a*b。最后+1表示运行主程序的前置处理器 如果两个元素相等或不相等,每个处理器将简单地进行比较。如果是,则返回
true
,否则返回false
。以[0]为例。我们只是比较B的任何元素是否等于A[0]。因此,我们将A[0]和B[0]传递给第一个处理器,将A[0]和B[1]传递给第二个处理器,依此类推,并对结果执行OR运算。相应地,将在每个核心上运行的test()
方法的代码如下:
public static bool test (int aElement, int bElement)
{
return aElement == bElement;
}
接下来我们对[1]做同样的处理,然后是[2]。。直到A[A-1]它们都并行
我们对这一结果进行了反复分析,如:
(test(A[0], B[0]) || test(A[0], B[1])...) && (test(A[1], B[0]) || test(A[1], B[1])... )
因此,Main()
将如下所示:
public void Main (string[] args)
{
//Read A and B arrays and create the next line dynamically
var allPresent = (test(A[0], B[0]) || test(A[0], B[1]) ||... test(A[0], B[b-1]))
&& (test(A[1], B[0]) || test(A[1], B[1]) ||... test(A[1], B[b-1]))
.
.
.
&& (test(A[a-1], B[0]) || test(A[a-1], B[1]) ||... test(A[a-1], B[b-1]))
Console.WriteLine("All Elements {0}", (allPresent ? "Found" : "Not Found"));
}
我们并行生成所有的
测试(A[k],B[l])
,在O(1)时间内给出结果。找到的中间数组需要什么<代码>如果[i]==A[j]结果=true就足够了。@yvesdao不一定。发现[我]必须对我所有的人都是真实的。至少我是这样理解这个问题的:A和B中可以有重复的元素吗?要真正得到解决方案O(logn),你需要描述如何在O(logn)时间内将这些n个CPU的答案组合成一个“是/否”答案。例如,您可以将CPU排列成二叉树结构,以便两个“子”CPU将其结果传递给共享的父CPU,共享的父CPU将结果传递到树上的根,根CPU计算最终答案。@displayName是的,可能有。@j_random_hacker因此汇总答案应导致额外的O(logn)时间?@SieKensou:那么请看看我的解决方案,让我知道你没有得到什么…还需要一个CPU来检查a的每个元素是在B的第一个元素之前,还是在最后一个元素之后。不过,这并没有太大的改变。我仍然认为你需要某种方法在O(1)时间内收集所有这些答案……当一个内核在值之间找到一个元素时,它可以向第一个内核发送信号(可能设置一个共享内存位),所以这就是O(1)。为了证明序列不匹配,您只需要第一个失败的例子,并且您知道如果没有人在一个周期内设置位,那么序列是好的@j_随机_hacker@IanMercer:根据Niklas B.的回答,如果我们有CRCW模型,这似乎是可行的,因为任何写入都会写入相同的值。我怀疑如果不允许并发、等值写入,那么就不可能有O(1)解决方案……我不太明白如何在O(1)时间内完成或超过结果?@SieKensou:更新了我的答案。感谢更新:)我知道如何在O(1)中完成所有测试(A[k],B[l]),但是为什么在ab元素上执行OR和and的过程需要O(1)时间而不是O(ab)?是否使用了一些特殊技术?@SieKensou:如果我对你说实话,这些问题对我来说似乎是错误的。因为,即使要测试A的元素,您也必须至少读取所有元素,这至少需要O(A)时间。然而,我假设通过某种魔法,数组的正确部分以恒定的时间到达处理器。没有使用特殊的技术。这是一个经常性的和或假定的失败和成功更快。。。与if one和isfalse
类似,整个表达式都是false
,如果one或istrue
,则OR不会进一步求值并被视为true
@SieKensou:AND和OR需要一个位(设置为0或1),