我决定减少在数组中查找元素所需的比较次数。在这里,我们用搜索元素本身替换列表的最后一个元素,并运行while循环以查看列表中是否存在搜索元素的任何副本,并在找到搜索元素后立即退出循环。请参阅代码段进行澄清。
import java.util.Random;
public class Search {
public static void main(String[] args) {
int n = 10000000;
int key = 10000;
int[] arr = generateRandomSize(n);
long start = System.nanoTime();
int find = sentinels(arr, key);
long end = System.nanoTime();
System.out.println(find);
System.out.println(end - start);
arr = generateRandomSize(n);
start = System.nanoTime();
find = linear(arr, key);
end = System.nanoTime();
System.out.println(find);
System.out.println(end - start);
}
public static int[] generateRandomSize(int n) {
int[] arr = new int[n];
Random rand = new Random();
for (int i = 0; i < n; ++i) {
arr[i] = rand.nextInt(5000);
}
return arr;
}
public static int linear(int[] a, int key) {
for(int i = 0; i < a.length; ++i) {
if (a[i] == key) {
return i;
}
}
return -1;
}
public static int sentinels(int[] a, int key) {
int n = a.length;
int last = a[n-1];
a[n-1] = key;
int i = 0;
while (a[i] != key) {
++i;
}
a[n-1] = last;
if ((i < n - 1) || a[n-1] == key ) {
return i;
}
return -1;
}
}
因此,使用哨兵搜索,我们不会像i
答案 0 :(得分:3)
您将不得不查看字节码,甚至更深入地了解由此产生的热点。但是我很确定这个说法是不正确的:
使用前哨搜索,我们没有像我那样做10000000次比较< 长度
为什么?因为当您访问a[i]
时,i
必须进行边界检查。另一方面,在线性情况下,优化器可以推断出可以省略边界检查,因为它“知道” i>=0
(由于循环结构)以及i<arr.length
,因为它已经被在循环条件下进行了测试。
因此,哨兵方法只会增加开销。
这使我想到了大约20年前进行的智能C ++优化(称为“模板元编程”和“表达模板”),从而缩短了执行时间(以更高的编译时间为代价),之后在发布了下一个编译器版本时,我发现新版本能够优化原始源,以产生完全相同的程序集-简而言之,我应该宁愿以不同的方式使用我的时间,而是使用更具可读性(易于维护)的版本代码。