以下数组的排序没有重复(包含独特的正整数),小尺寸(小于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
语句。
答案 0 :(得分:1)
我认为您无法提高Java代码的性能。但是,我会注意到它与C版本没有做同样的事情。 C版本将交集放入由调用者预先分配的数组中。 Java版本自己分配数组...然后在完成时重新分配并复制到较小的数组。
我想,您可以更改Java版本以对输入数组进行两次传递,第一次确定输入数组需要多大...但它是否有帮助或阻碍将取决于输入。
可能还有其他特殊情况可以优化;例如如果在一个数组中可能存在长数字,而另一个数组中没有任何数字,那么您可以“乐观地”尝试一次跳过多个数字;即将i
或j
增加一个大于1
的数字。
但是他们提到“使用无分支实现可以改进这种方法”。怎么会这样呢?使用开关?
不是Java切换...或条件表达式,因为它们在转换为本机代码时都涉及分支。
我认为他指的是这样的话:Branchless code that maps zero, negative, and positive to 0, 1, 2
FWIW尝试用Java做这种事情是个坏主意。问题在于类似棘手的代码序列的性能取决于硬件架构,指令集,时钟计数等的细节,这些细节从一个平台到另一个平台是不同的。 Java JIT编译器的优化器可以很好地优化代码......但如果你包含棘手的序列:
话虽如此,Java的未来版本可能包含一个超级优化器并不是不可能的......就像上面链接的Q&amp; A中提到的一样......它将能够自动生成无分支序列。但请记住,超级优化是非常昂贵的。
答案 1 :(得分:0)
也许使用? :
运算符:
(a[i] < b[j]) ? i++ : ((a[i] > b[j]) ? j++ : ....