【问题标题】:How to speed up array intersection in Java?如何加快Java中的数组交集?
【发布时间】:2013-05-09 11:33:50
【问题描述】:

下面的数组是排序的,没有小尺寸(小于 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] &lt; b[j]a[i] &gt; b[j]a[i] == b[i] 替换为整数操作数上的二进制运算?

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

【问题讨论】:

    标签: java arrays performance intersection


    【解决方案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 编译器原本可以执行的有用优化。

    话虽如此,Java 的某些未来版本可能会包含一个超级优化器……就像上面链接的问答中提到的那样……它能够自动生成无分支序列,这并非不可能。但请记住,执行超级优化非常昂贵。

    【讨论】:

      【解决方案2】:

      也许使用? : 运算符:

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

      【讨论】:

      • 三元运算符和if-else完全一样
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-08
      • 2011-01-07
      • 1970-01-01
      • 2013-07-25
      • 1970-01-01
      • 2013-11-08
      • 1970-01-01
      相关资源
      最近更新 更多