有可能比线性搜索更快的算法?

pro*_*rs5 8 java algorithm search

我听说没有比线性搜索更快的算法(对于未排序的数组),但是,当我运行这个算法(线性)时:

public static void search(int[] arr, int value){
    for(int i = 0; i < arr.length; i++){
        if(arr[i] == value) return;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用长度为1000000的随机数组,查找值的平均时间为75ns,但使用此算法:

public static void skipSearch(int[] arr, int value){
    for(int i = 0; i < arr.length; i+=2){
        if(arr[i] == value) return;
    }
    for(int i = 1; i < arr.length; i+=2){
        if(arr[i] == value) return;
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到一个更短的平均值,68ns?

编辑:很多人说我没有做适当的基准测试,这是侥幸的,但我运行了1000000次这些功能并得到了平均值.每次运行1000000次函数时,第一个算法得到75-76ns,第二个算法得到67-69ns.

我用java System.nanoTime() 来测量它.

码:

int[] arr = new int[1000];
Random r = new Random();
for(int i = 0; i < arr.length; i++){
    arr[i] = r.nextInt();
}
int N = 1000000;
long startTime = System.nanoTime();
for(int i = 0; i < N; i++){
    search(arr, arr[(int) Math.floor(Math.random()*arr.length)]);
}
System.out.println("Average Time: "+(System.nanoTime()-startTime)/(float)N+"ns");
startTime = System.nanoTime();
for(int i = 0; i < N; i++){
    skipSearch(arr, arr[(int) Math.floor(Math.random()*arr.length)]);
}
System.out.println("Average Skip Search Time: "+(System.nanoTime()-startTime)/(float)N+"ns");
Run Code Online (Sandbox Code Playgroud)

Hon*_*dek 31

很可能,因为你的search()方法没有返回任何东西,并且循环中没有任何动作,JVM中的JIT编译器会优化代码 - 换句话说,在将字节代码加载到JVM之前修改字节代码,以便你的search()方法很可能不会(几乎)做任何事情.哪个是最重要的,它可能也完全消除了循环.JIT优化是非常聪明,它可以找出很多的情况下,当它不需要加载任何代码转换成JVM(但是代码在字节码.class文件).

然后你只测量随机数 - 而不是你的方法的实时复杂性.

阅读例如如何确保没有jvm和编译器优化发生,应用它并再次运行您的基准测试.

也改变你的search()方法,使它们返回索引 - 从而使优化器的生命更难.但是,有时创建一个无法优化的代码却非常困难:)关闭优化(如上面的链接)更可靠.


通常,对未经优化的代码进行基准测试是没有意义的.然而,在这种情况下,OP想要测量理论算法.他想测量实际的传球次数.他必须确保实际执行循环.这就是他应该关闭优化的原因.

OP认为他所测量的是算法的速度,而事实上算法根本没有机会运行.在这种特殊情况下关闭JIT优化可以修复基准.

  • 这个命题不是为了运输代码而关闭优化,而是在禁用优化的情况下运行基准测试,以便OP可以获得线性搜索在真实场景中确实更快的证据. (4认同)
  • 雅,不; 除非您计划在禁用优化的情况下运送代码,否则您无法关闭优化并对结果进行*任何*有用的性能声明.您认为代码优化无所事事的观点是好的; 你通过关闭优化"修复此问题"的建议很糟糕.如果您无法生成编译器无法优化的任务,则无论如何都不应对其进行基准测试并从中得出结论. (2认同)
  • 即使是像这样的理论情况,关闭优化也不是一种有效的测量方法.相反,您需要包含约束以便实际使用输出(例如将结果打印为定时测量的一部分)并使用非常量输入,以便整个事物不能被恒定折叠.您*希望*知道优化代码的运行速度,而不是"未优化"的速度有多快(一个更好的词会"悲观",因为没有精心设计的编译器实际上以自然的方式产生"未优化"的代码代码运行. (2认同)
  • 你忽略了这一点,假设优化中的特殊性导致自定义搜索优于线性搜索.因此,为什么这个命题是关闭所述优化,以便可以看到差异.正如@R ..所述,强制实际使用代码是一个更好的解决方案,但Honza Zidek并没有建议*修复*他建议一种方法*反驳OP的理论. (2认同)

Col*_*oen 18

这就是为什么我们不关心字面上计算执行时间需要多长时间,以及随着输入复杂性的增加,事物的规模增长.看看渐近运行时分析:

https://en.wikipedia.org/wiki/Analysis_of_algorithms


vvg*_*vvg 7

什么是统计数据value?在你的情况下,它很可能甚至是值.很明显,对于这两种情况,算法的复杂性O(n)O(n/2) + O(n/2)几乎相同 - 线性时间

  • 甚至没有价值,但它出现在偶数指数上. (2认同)

bud*_*udi 5

它只是偶然的"更快".您可能注意到的是,您的值更常出现在偶数索引上,而不是奇数索引上.