有人可以给我一个实际的例子,其中O(N*N)
算法比某些O(N)
的{{1}}算法更快。
编辑:我认为这个问题因过于笼统而被搁置。但我确实只有一般性问题。没有其他方式可以以不同的方式提出这个问题。
答案 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 answer至this 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)算法。