为什么哨兵搜索比线性搜索慢?

时间:2019-04-27 07:31:38

标签: java algorithm search optimization

我决定减少在数组中查找元素所需的比较次数。在这里,我们用搜索元素本身替换列表的最后一个元素,并运行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

1 个答案:

答案 0 :(得分:3)

您将不得不查看字节码,甚至更深入地了解由此产生的热点。但是我很确定这个说法是不正确的:

  

使用前哨搜索,我们没有像我那样做10000000次比较<   长度

为什么?因为当您访问a[i]时,i必须进行边界检查。另一方面,在线性情况下,优化器可以推断出可以省略边界检查,因为它“知道” i>=0(由于循环结构)以及i<arr.length,因为它已经被在循环条件下进行了测试。

因此,哨兵方法只会增加开销。

这使我想到了大约20年前进行的智能C ++优化(称为“模板元编程”和“表达模板”),从而缩短了执行时间(以更高的编译时间为代价),之后在发布了下一个编译器版本时,我发现新版本能够优化原始源,以产生完全相同的程序集-简而言之,我应该宁愿以不同的方式使用我的时间,而是使用更具可读性(易于维护)的版本代码。