Java 为什么这个O(N^2)算法运行得这么快?

Java 为什么这个O(N^2)算法运行得这么快?,java,algorithm,complexity-theory,big-o,time-complexity,Java,Algorithm,Complexity Theory,Big O,Time Complexity,这个算法是O(n2),但是它运行不到一秒钟。为什么这么快 public class ScalabilityTest { public static void main(String[] args) { long oldTime = System.currentTimeMillis(); double[] array = new double[5000000]; for ( int i = 0; i < array.length; i++ ) {

这个算法是O(n2),但是它运行不到一秒钟。为什么这么快

public class ScalabilityTest {

   public static void main(String[] args) {
      long oldTime = System.currentTimeMillis();
      double[] array = new double[5000000];

      for ( int i = 0; i < array.length; i++ ) {
         for ( int j = 0; j < i; j++ ) {
            double x = array[j] + array[i];
         }
      }
      System.out.println( (System.currentTimeMillis()-oldTime) / 1000 );
   }
}
公共类可伸缩性测试{
公共静态void main(字符串[]args){
long oldTime=System.currentTimeMillis();
double[]数组=新的double[5000000];
for(int i=0;i
编辑:

我将代码修改为以下内容,现在运行速度非常慢

public class ScalabilityTest {

public static void main(String[] args) {
    long oldTime = System.currentTimeMillis();
    double[] array = new double[100000];
    int p = 2;
    int m = 2;
    for ( int i = 0; i < array.length; i++ ) {
        p += p * 12348;
        for ( int j = 0; j < i; j++ ) {
            double x = array[j] + array[i];
            m += m * 12381923;
        }
    }

    System.out.println( (System.currentTimeMillis()-oldTime) / 1000 );
    System.out.println( p + ", " + m );
    }

}
公共类可伸缩性测试{
公共静态void main(字符串[]args){
long oldTime=System.currentTimeMillis();
double[]数组=新的double[100000];
int p=2;
int m=2;
for(int i=0;i
我认为这里的问题是一切都在优化。我的理由如下:

  • x
    的值无需进行任何计算即可知道-您的数组都是0,因此
    x
    将始终取0
  • 局部变量
    x
    未使用,可以进行优化
  • 内部循环不起任何作用,因此可以进行优化
  • 外部循环不起任何作用,因此可以进行优化
  • 剩下的代码不多,这就是为什么它可能运行得如此之快

    作为参考,我在自己的机器上尝试了这一点,通过不断地将数组大小乘以10的系数来改变数组大小,并且发现性能绝对没有变化-它总是完成并输出需要0秒的时间。这与优化假设一致,即运行时应为O(1)

    编辑:您编辑的代码进一步支持了我的想法,因为现在循环体有副作用,因此无法优化。具体地说,由于
    m
    p
    在循环内部更新,编译器无法轻松优化整个循环,因此您将开始看到O(n2)性能。试着改变数组的大小,看看会发生什么


    希望这有帮助

    可能是JIT起作用并优化了事情,因为双循环实际上什么都不做

    注意,这对于Java和JVM的每个版本和实现来说都太具体了——在我的版本上,它现在运行了大约一分钟

    您可以添加一个

    System.out.println(x)
    

    如果希望看到O(N^2)的行为,请在for循环之后和外部停止优化

    算法的顺序不能告诉您它的运行速度。它告诉你当n的大小改变时,它的速度是如何变化的


    O(n)=n^2意味着,如果你尝试使用10000000个元素,你将需要(大约)当前所需时间的4倍。

    我认为这是不相关的。O(n^2)更快,但与什么有关。 你只能说某事很快,只有当你把它与某事比较时。不是吗

    此外,时间也取决于输入大小。尝试一个较大的输入,您可以看到O(N)和O(N^2)之间的差异

    供实际参考。是一个编程竞赛网站,使用两个处理器根据输入文件检查代码

  • (英特尔奔腾III 733 MHz)-由旧的固态奔腾III机器组成,自2004年开始为SPOJ提供服务。由于这些机器速度较慢,SPOJ问题解决者创建的法官可以更轻松地测试解决方案中使用的算法的复杂性,而无需创建大量数据集(您可以很容易地分辨出O(n)和O(nlogn)之间的差异)

  • (英特尔奔腾G860 3GHz)-此新群集由现代快速的英特尔奔腾G860 CPU组成。在这方面,您的提交速度将比上一次快30到50倍。所以您可以预期,如果您在家测试您的解决方案,那么它在SPOJ上的执行时间将类似。在此群集上,提交的内存限制为1536 MB

  • 更多: 通常,在英特尔奔腾G3860 3GHZ上,循环在1秒内最多运行10^7次。所以10^7的O(N)算法只需要1秒。 现在取N=10^7,做O(N^2)并试一下。。你可以自己体验时差

    编译器优化在这方面也起着重要作用!!
    你的代码太简单了!你的数组是空的

    计时只有在其他算法的上下文中才有意义,它应该运行多快/多慢?
    O(n^2)
    与实际花费的时间无关,只是时间根据输入大小增长的速度。尝试更改5000000并根据大小绘制时间,以检查近似增长率。@arynaq实际上不是。对于给定的
    n
    ,O(n)=n^2的算法可能比O(n)=n^3的算法慢。O(n)告诉我们,对于足够大的
    n
    算法,第一种算法最终会比第二种算法快,但
    n
    可能不实用(例如,如果解决
    n
    大小问题的执行时间太长)。当然,随着硬件速度的提高,达到收支平衡的
    n
    值所需的时间逐渐减少,因此它不是绝对的。我并不反对:)我只是指出“快”和“慢”是相对的术语,如果你想称一个算法为快还是慢,你应该能够回答“与什么相比?”5000000可能足以让N^2算法运行一段时间。这根本不能回答问题,如果OP的意思是“为什么计算机可以在一秒钟内运行5000000^2次运算”。@ZiyaoWei OP给人的印象是