如何以最快的方式交叉两个排序的数组?

Den*_*gin 5 java arrays sorting algorithm merge

我有两个巨大的排序数组(每个~100K项).我需要非常快地交叉它们.现在我以标准的方式做到这一点:

  • 如果a [i] <b [j]则i ++
  • 如果a [i]> b [j]那么j ++
  • else:在交集,i ++,j ++中添加[i]

但是完成时间太长(~350微秒),导致整体性能相当差.有没有办法更快地做到这一点?

PS交叉口尺寸不大于1000件(平均而言),我只需要25到100件.

bti*_*lly 2

并行运行 2 100k 数组需要大约 200k 次比较。您目前正在 350 微秒 = 350k 纳秒内完成它。所以每次比较时间不到 2 纳秒。如果您的 CPU 约为 4 GHz,则为 8 个时钟周期。

那挺好的。您可以尝试变得复杂,检测运行等,但管道停顿对您自己的伤害可能比节省的工作量更大。

只有两种方法可以加快速度。减少工作量,或增加更多工人。

您已经表明减少工作量是可行的,这就是 Tamas Hegedus 建议的原因。不要创建交集,而是创建一个Iterator将返回交集中的下一个事物的交集。这将要求您重写使用所述迭代器的逻辑,但您将完成当前计算的 10% 以下。这将快近 10 倍。

至于添加工作线程,您需要在工作线程之间分配工作并防止它们相互干扰。对于k小型(不大于 CPU 数量!),数组大小为对数工作量,您可以执行快速选择来查找将k-1组合数组分成k偶数块的值(oops Adapt http://www .geeksforgeeks.org/median-of-two-sorted-arrays/而不是进行快速选择...),以及每个数组中这些值的索引。这就产生了k同样困难的问题,每个问题都可以指定为 4 个数字。启动k线程并让每个线程都得到一部分答案。这将比k您当前所做的快大约几倍。

可以将这些方法结合起来,但需要付出更多的努力。你要做的就是让迭代器创建 4 个工作线程,并向每个工作线程分发块。当你调用iter.next()迭代器时,如果它有一个值,它就会给你一个下一个值。如果没有,它将等待正在生成下一个块的工作人员完成,抓取该块,如果准备好,则将另一个块交给该工作人员,然后分发该块中的第一个值。您可以使用块大小。您希望它足够大,以便 CPU 能够很好地确定它应该从 RAM 流式传输到 CPU 缓存,并且不会认为线程之间存在同步争用。

我的猜测是,考虑到大小和同步限制,混合方法不会比迭代器方法有太大的优势(如果有的话)。但如果你真的很绝望,你可以尝试一下。