在Matters Computational中,我发现了这个有趣的线性搜索实现(它实际上是我的Java实现; - )):
public static int linearSearch(int[] a, int key) {
int high = a.length - 1;
int tmp = a[high];
// put a sentinel at the end of the array
a[high] = key;
int i = 0;
while (a[i] != key) {
i++;
}
// restore original value
a[high] = tmp;
if (i == high && key != tmp) {
return NOT_CONTAINED;
}
return i;
}
它基本上使用了一个Sentinel,它是搜索的值,因此您始终可以找到该值,而不必检查数组边界。最后一个元素存储在temp变量中,然后将sentinel放在最后一个位置。当找到该值时(记住,它总是由于sentinel而找到),原始元素将被恢复,并且如果它代表最后一个索引并且与搜索的值不相等则检查索引。如果是这种情况,则返回-1(NOT_CONTAINED),否则返回索引。
虽然我发现这个实现非常聪明,但我想知道它是否真的有用。对于小型数组,它似乎总是较慢,而对于大型数组,当找不到该值时,它似乎更快。有什么想法吗?
修改
最初的实现是用C ++编写的,所以可以有所作为。
答案 0 :(得分:10)
这不是线程安全的,例如,您可以通过在第一个线程从第一个线程开始a[high]
更改为{{1}后开始丢失a[high]
值},所以会将key
记录到key
,并在第一个线程将tmp
恢复为原始值后完成。第二个线程将a[high]
恢复为它第一次看到的内容,这是第一个线程的a[high]
。
它在java中也没用,因为JVM会在你的数组中包含边界检查,所以你的while循环正在检查你是不是要经过数组的末尾。
答案 1 :(得分:7)
你会注意到它的速度增加吗?否
你会注意到缺乏可读性吗?是
您是否会注意到可能导致并发问题的不必要的数组突变?是
过早优化是万恶之源。
答案 2 :(得分:5)
似乎没有特别有用。这里的“创新”只是通过将其与匹配测试相结合来摆脱迭代测试。现代处理器现在花费0次进行迭代检查(所有计算和分支都与匹配测试代码并行完成)。
在任何情况下,二进制搜索都会在大型数组上使用此代码,并且在小型数组上具有可比性。线性搜索是20世纪60年代的。
答案 3 :(得分:2)
哨兵搜索可以追溯到Knuth。它的价值在于它将循环中的测试次数从两个减少(“密钥匹配吗?我最后?”)只减少一个。
是的,它很有用,因为它可以通过消除条件分支错误预测来显着减少适度大小无序数组的搜索时间。这也减少了此类数组的插入时间(OP未显示的代码),因为您不必订购商品。
如果你有更大的有序项目数组,二进制搜索会更快,代价是更大的插入时间,以确保数组的排序。
对于更大的集合,哈希表将是最快的。
真正的问题是阵列大小的分布是什么?
答案 4 :(得分:2)
另见'在非洲寻找老虎'这个笑话 Punchline =一位经验丰富的程序员将老虎放在cairo中,以便搜索终止。
答案 5 :(得分:0)
是的 - 这是因为while循环没有2次比较,而不是标准搜索。
它快两倍。它在Knuth Vol 3中作为优化。