O(N * N)能否比O(N)快

时间:2015-10-26 18:16:33

标签: algorithm big-o

有人可以给我一个实际的例子,其中O(N*N)算法比某些O(N)的{​​{1}}算法更快。

编辑:我认为这个问题因过于笼统而被搁置。但我确实只有一般性问题。没有其他方式可以以不同的方式提出这个问题。

4 个答案:

答案 0 :(得分:2)

可能有些人试图更快地制作O(N * N)算法(例如通过引入一些数据预处理)并最终得到类似的结果:

O(N):

for (int i=0;i<N;i++){
    // do some expensive preconditioning of your data
    // to enable using O(N) algorithm
}
for (int i=0;i<N;i++){
    // run the actual O(N) algorithm
}

O(N * N):

for (int i=0;i<N;i++){
    for (int j=0;j<N;j++){
        // run the O(N*N) algorithm
    }
}

大O符号只是大N的限制行为。常数(或线性)部分可能差别很大。例如,它可能是

O(N)   =           N + 10000 
O(N*N) = N^2 + 0.5*N +    10

答案 1 :(得分:1)

  

有人能给我一个现实的例子,其中O(N * N)算法比某些N> 10的O(N)算法快。

大O符号仅描述算法的渐近性能,N趋向正无穷大。

最重要的是:它描述了算法的理论性能 - 而不是其实际实现!

这就是为什么大O符号中省略了与其他开销相关的常量和次要函数的原因。它们与主要函数的形状无关(特别是当N倾向于无穷大时) - 但它们对于分析算法实现的真实世界性能至关重要。

简单的例子。将sleep(60)放在qsort()函数中。渐近地,该算法仍然是相同的O(N*log(N))算法,因为与无穷大相比,恒定的60秒睡眠是微不足道的。但实际上,这样的qsort()实现将超过任何冒泡排序实现(当然没有sleep()),因为现在在N*log(N)前面巨大常数。

答案 2 :(得分:0)

输入是整数n。

第一个例子:一对使用O表示法是上限的短程序,因此O(1)的程序也是O(n)和O(n ^ 2)等...

计划1:

def prog1(n)
    1.upto(n) do |i|
    end
end

计划2:

def prog2(n)
    return
end

程序1是O(n),程序2是O(n * n)以及O(n)和O(1)和O(n ^ n ^ n ^ n ^ n)。

然而,程序2比程序1更快。

第二个例子:一对使用O符号取决于行为的事实,因为n变大了。

计划1:与之前相同

计划2:

def prog2(n)
    if n < 10^100
        return
    else
        1.upto(n) do |i|
            1.upto(n) do |j|
            end
        end
    end
end

程序1是O(n),程序2是O(n * n)。

然而,程序2比程序更快,直到n> = 10 ^ 100。

答案 3 :(得分:0)

作为一个现实的示例,请参阅my answerthis question

N 编号的中位数可以在 O(N)时间内找到(在最坏情况下,或平均而言)。例如,这种算法在std::nth_element中实现。

然而,对于小 N ,提议的 O(N ^ 2)复杂度的算法可以运行得更快,因为1)它没有分支,2)它可以是用SSE矢量化。至少,对于short类型的 N = 23 元素,它在4-5次中优于std::nth_element。此特定设置适用于图像处理。

PS 顺便说一下,当{em> N&lt; = 32 时,std::nth_element的实现通常会在内部使用插入排序,这也是 O( N ^ 2)算法。