如何加速Java中的数组交集?

时间:2013-05-09 11:33:51

标签: java arrays performance intersection

以下数组的排序没有重复(包含独特的正整数),小尺寸(小于5000)和交叉(见下文)被称为十亿次,因此任何微优化都很重要。这个article很好地描述了如何使用C语言加速以下代码。

int i = 0, j = 0, c = 0, la = a.length, lb = b.length;
intersection = new int[Math.min(la, lb)];
while (i < la && j < lb) {
    if (a[i] < b[j]) i++;
    else if (a[i] > b[j]) j++;
    else {
        intersection[c] = a[i];
        i++; j++; c++;
    }
}
int[] intersectionZip = new int[c];
System.arraycopy(intersection, 0, intersectionZip, 0, c);

在Java中我猜这些低级指令是不可能的。但是他们提到“使用无分支实现可以改进这种方法”。怎么会这样呢?使用switch?或者可以将a[i] < b[j]a[i] > b[j]a[i] == b[i]比较替换为整数操作数上的二元运算?

二元搜索方法(复杂度为O(la log(lb)))并非如此,因为la不是<<而是lb。有趣的是如何更改if语句。

2 个答案:

答案 0 :(得分:1)

我认为您无法提高Java代码的性能。但是,我会注意到它与C版本没有做同样的事情。 C版本将交集放入由调用者预先分配的数组中。 Java版本自己分配数组...然后在完成时重新分配并复制到较小的数组。

我想,您可以更改Java版本以对输入数组进行两次传递,第一次确定输入数组需要多大...但它是否有帮助或阻碍将取决于输入。

可能还有其他特殊情况可以优化;例如如果在一个数组中可能存在长数字,而另一个数组中没有任何数字,那么您可以“乐观地”尝试一次跳过多个数字;即将ij增加一个大于1的数字。


  

但是他们提到“使用无分支实现可以改进这种方法”。怎么会这样呢?使用开关?

不是Java切换...或条件表达式,因为它们在转换为本机代码时都涉及分支。

我认为他指的是这样的话:Branchless code that maps zero, negative, and positive to 0, 1, 2

FWIW尝试用Java做这种事情是个坏主意。问题在于类似棘手的代码序列的性能取决于硬件架构,指令集,时钟计数等的细节,这些细节从一个平台到另一个平台是不同的。 Java JIT编译器的优化器可以很好地优化代码......但如果你包含棘手的序列:

  1. 将它们转换为本机代码并不是很明显或可预测的,
  2. 您可能会发现棘手实际上会抑制JIT编译器可能会执行的有用优化。
  3. 话虽如此,Java的未来版本可能包含一个超级优化器并不是不可能的......就像上面链接的Q&amp; A中提到的一样......它将能够自动生成无分支序列。但请记住,超级优化是非常昂贵的。

答案 1 :(得分:0)

也许使用? :运算符:

  (a[i] < b[j]) ? i++ : ((a[i] > b[j]) ? j++ : ....