这种线性搜索实现真的有用吗?

hel*_*hod 1 algorithm

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;
}
Run Code Online (Sandbox Code Playgroud)

它基本上使用了一个sentinel,它是搜索的值,因此您总是可以找到该值,而不必检查数组边界.最后一个元素存储在temp变量中,然后将sentinel放在最后一个位置.当找到该值时(记住,它总是由于sentinel而找到),原始元素将被恢复,并且如果它代表最后一个索引并且与搜索的值不相等则检查索引.如果是这种情况,则返回-1(NOT_CONTAINED),否则返回索引.

虽然我发现这个实现非常聪明,但我想知道它是否真的有用.对于小型数组,它似乎总是较慢,而对于大型数组,当找不到该值时,它似乎更快.有任何想法吗?

编辑

最初的实现是用C++编写的,所以这可能会有所不同.

Ste*_*nne 10

它不是线程安全的,例如,你可以a[high]通过在第一个线程更改a[high]为第二个线程之后开始丢失你的值key,因此将记录keytmp,并在第一个线程恢复a[high]到其原始值之后完成.第二个线程将恢复a[high]到它第一次看到的内容,这是第一个线程key.

它在java中也没用,因为JVM将在你的数组上包含边界检查,因此你的while循环检查你是否还没有超越数组的末尾.

  • 实际上关于绑定检查,这个方法肯定会慢一些,因为我没有看到JVM(不是javac)如何消除它们,而我观察到在迭代中测试,例如"int n = a.length; for(int i = 0; i <n; ++ i)process(a [i])"它确实如此. (2认同)

eri*_*len 7

你有没有注意到它的速度增加?没有

你会注意到缺乏可读性吗?是

您是否会注意到可能导致并发问题的不必要的数组突变?是

过早优化是万恶之源.


Kei*_*all 5

似乎没有特别有用.这里的"创新"只是通过将其与匹配测试相结合来摆脱迭代测试.如今,现代处理器在迭代检查上花费了0倍的时间(所有计算和分支都与匹配测试代码并行完成).

在任何情况下,二进制搜索都会在大型数组上启动此代码,并且在小型数组上具有可比性.线性搜索是20世纪60年代.

  • 如果数组未排序并且您只需要找到几个值,则线性搜索优于二分搜索.迭代检查时间很短,但在我的经验中并非零.例如,通过最近在C++快速排序实现中消除一些迭代检查,我能够在时间上获得几个百分点的改进.是的,二进制搜索当然是一种方法,如果您的数组已排序,或者如果您需要经常搜索数组,最好排序和使用二进制搜索. (3认同)