简体   繁体   English

时间复杂度 (Big O) - 当我们有 2 个嵌套的 FOR 循环时,N 的值能否决定时间复杂度是 O(1) 还是 O(N)?

[英]Time Complexity (Big O) - Can value of N decides whether the time complexity is O(1) or O(N) when we have 2 nested FOR loops?

Suppose that I have 2 nested for loops, and 1 array of size N as shown in my code below:假设我有 2 个嵌套的 for 循环和 1 个大小为 N 的数组,如下面的代码所示:

int result = 0;

for( int i = 0; i < N ; i++)
{
    for( int j = i; j < N ; j++)
    {
        result = array[i] + array[j]; // just some funny operation
    }
}

Here are 2 cases:这里有2个案例:

(1) if the constraint is that N >= 1,000,000 strictly, then we can definitely say that the time complexity is O(N^2). (1) 如果严格的约束条件是 N >= 1,000,000,那么我们可以肯定地说时间复杂度是 O(N^2)。 This is true for sure as we all know.众所周知,这是真的。

(2) Now, if the constraint is that N < 25 strictly, then people could probably say that because we know that definitely, N is always too small, the time complexity is estimated to be O(1) since it takes very little time to run and complete these 2 for loops WITH MODERN COMPUTERS ? (2) 现在,如果严格的约束条件是 N < 25,那么人们可能会说,因为我们肯定知道,N 总是太小,所以时间复杂度估计为 O(1),因为它只需要很少的时间用现代计算机运行和完成这 2 个 for 循环? Does that sound right?听起来对吗?

Please tell me if the value of N plays a role in deciding the outcome of the time complexity O(N)?请告诉我 N 的值是否在决定时间复杂度 O(N) 的结果中起作用? If yes, then how big the value N needs to be in order to play that role (1,000? 5,000? 20,000? 500,000?) In other words, what is the general rule of thumb here?如果是,那么 N 值需要多大才能发挥这个作用(1,000?5,000?20,000?500,000?)换句话说,这里的一般经验法则是什么?


INTERESTING THEORETICAL QUESTION: If 15 years from now, the computer is so fast that even if N = 25,000,000, these 2 for loops can be completed in 1 second.有趣的理论问题:如果 15 年后,计算机速度如此之快,即使 N = 25,000,000,这 2 个 for 循环也可以在 1 秒内完成。 At that time, can we say that the time complexity would be O(1) even for N = 25,000,000?那时,我们可以说即使 N = 25,000,000,时间复杂度也是 O(1) 吗? I suppose the answer would be YES at that time.我想当时的答案是肯定的。 Do you agree?你同意吗?

tl:dr No. The value of N has no effect on time complexity. tl:dr 没有。N 的值对时间复杂度没有影响。 O(1) versus O(N) is a statement about "all N" or how the amount of computation increases when N increases. O(1) 与 O(N) 是关于“所有 N”或当 N 增加时计算量如何增加的陈述。

Great question.好问题。 It reminds me of when I was first trying to understand time complexity.这让我想起了我第一次尝试理解时间复杂度的时候。 I think many people have to go through a similar journey before it ever starts to make sense so I hope this discussion can help others.我认为很多人必须通过类似的旅程 go 才开始有意义,所以我希望这个讨论可以帮助其他人。

First of all, your "funny operation" is actually funnier than you think since your entire nested for-loops can be replaced with:首先,您的“有趣操作”实际上比您想象的更有趣,因为您的整个嵌套 for 循环都可以替换为:

result = array[N - 1] + array[N - 1]; // just some hilarious operation hahaha ha ha

Since result is overwritten each time, only the last iteration effects the outcome.由于每次都会覆盖result ,因此只有最后一次迭代会影响结果。 We'll come back to this.我们会回到这个。

As far as what you're really asking here, the purpose of Big-O is to provide a meaningful way to compare algorithms in a way that is indenependent of input size and independent of the computer's processing speed .就您在这里真正要问的而言,Big-O 的目的是提供一种有意义的方式来比较算法,这种方式与输入大小无关,也与计算机的处理速度无关 In other words, O(1) versus O(N) has nothing to with the size of N and nothing to do with how "modern" your computer is.换句话说,O(1) 与 O(N) 与 N 的大小无关,也与您的计算机的“现代”程度无关。 That all effects execution time of the algorithm on a particular machine with a particular input, but does not effect time complexity , ie O(1) versus O(N).所有这些都会影响算法在具有特定输入的特定机器上的执行时间,但不会影响时间复杂度,即 O(1) 与 O(N)。

It is actually a statement about the algorithm itself, so a math discussion is unavoidable, as dxiv has so graciously alluded to in his comment.它实际上是关于算法本身的陈述,所以数学讨论是不可避免的,正如 dxiv 在他的评论中如此亲切地提到的那样。 Disclaimer: I'm going to omit certain nuances in the math since the critical stuff is already a lot to explain and I'll defer to the mountains of complete explanations elsewhere on the web and textbooks.免责声明:我将省略数学中的某些细微差别,因为关键的东西已经有很多需要解释了,我将遵从 web 和教科书其他地方的大量完整解释。

Your code is a great example to understand what Big-O does tell us.您的代码是理解 Big-O 告诉我们的一个很好的例子。 The way you wrote it, its complexity is O(N^2).你写它的方式,它的复杂性是 O(N^2)。 That means that no matter what machine or what era you run your code in, if you were to count the number of operations the computer has to do, for each N, and graph it as a function, say f(N), there exists some quadratic function, say g(N)=9999N^2+99999N+999 that is greater than f(N) for all N.这意味着无论您在什么机器或哪个时代运行代码,如果您要计算计算机必须执行的操作数,对于每个 N,并将其绘制为 function,例如 f(N),则存在一些二次 function,例如 g(N)=9999N^2+99999N+999,对于所有 N 都大于 f(N)。

But wait, if we just need to find big enough coefficients in order for g(N) to be an upper bound, can't we just claim that the algorithm is O(N) and find some g(N)=aN+b with gigantic enough coefficients that its an upper bound of f(N)???但是等等,如果我们只需要找到足够大的系数以使 g(N) 成为上限,我们就不能声称该算法是 O(N) 并找到一些 g(N)=aN+b具有足够大的系数,它是 f(N) 的上限??? THE ANSWER TO THIS IS THE MOST IMPORTANT MATH OBSERVATION YOU NEED TO UNDERSTAND TO REALLY UNDERSTAND BIG-O NOTATION .对此的答案是您需要了解的最重要的数学观察,才能真正理解 BIG-O 表示法 Spoiler alert.剧透警报。 The answer is no.答案是不。

For visuals, try this graph on Desmos where you can adjust the coefficients:[https://www.desmos.com/calculator/3ppk6shwem][1]对于视觉效果,请在 Desmos 上尝试此图表,您可以在其中调整系数:[https://www.desmos.com/calculator/3ppk6shwem][1]

No matter what coefficients you choose, a function of the form aN^2+bN+c will ALWAYS eventually outgrow a function of the form aN+b (both having positive a).无论您选择什么系数,aN^2+bN+c 形式的 function 最终总是会超过 aN+b 形式的 function (两者都具有正 a)。 You can push a line as high as you want like g(N)=99999N+99999, but even the function f(N)=0.01N^2+0.01N+0.01 crosses that line and grows past it after N=9999900.您可以将一条线推到任意高,例如 g(N)=99999N+99999,但即使是 function f(N)=0.01N^2+0.01N+0.01 也会越过该线并在 N=9999900 之后越过该线。 There is no linear function that is an upper bound to a quadratic.没有线性 function 是二次方的上限。 Similarly, there is no constant function that is an upper bound to a linear function or quadratic function.同样,没有常数 function 是线性 function 或二次 function 的上限。 Yet, we can find a quadratic upper bound to this f(N) such as h(N)=0.01N^2+0.01N+0.02, so f(N) is in O(N^2).然而,我们可以找到这个 f(N) 的二次上界,例如 h(N)=0.01N^2+0.01N+0.02,所以 f(N) 在 O(N^2) 中。 This observation is what allows us to just say O(1) and O(N^2) without having to distinguish between O(1), O(3), O(999), O(4N+3), O(23N+2), O(34N^2+4+e^N), etc. By using phrases like "there exists a function such that" we can brush all the constant coefficients under the rug.这种观察使我们可以只说 O(1) 和 O(N^2) 而不必区分 O(1)、O(3)、O(999)、O(4N+3)、O(23N +2)、O(34N^2+4+e^N) 等。通过使用诸如“存在一个 function 使得”这样的短语,我们可以将所有常数系数都刷到地毯下。

So having a quadratic upper bound, aka being in O(N^2), means that the function f(N) is no bigger than quadratic and in this case happens to be exactly quadratic.因此,具有二次上界,也就是 O(N^2),意味着 function f(N) 不大于二次,在这种情况下恰好是二次的。 It sounds like this just comes down to comparing the degree of polynomials, why not just say that the algorithm is a degree-2 algorithm?听起来这只是比较多项式的次数,为什么不直接说该算法是 2 次算法呢? Why do we need this super abstract "there exists an upper bound function such that bla bla bla..."?为什么我们需要这个超级抽象“存在一个上限 function 使得 bla bla bla ...”? This is the generalization necessary for Big-O to account for non-polynomial functions, some common ones being logN, NlogN, and e^N.这是 Big-O 解释非多项式函数所必需的概括,一些常见的函数是 logN、NlogN 和 e^N。

For example if the number of operations required by your algorithm is given by f(N)=floor(50+50*sin(N)), we would say that it's O(1) because there is a constant function, eg g(N)=101 that is an upper bound to f(N).例如,如果您的算法所需的操作数由 f(N)=floor(50+50*sin(N)) 给出,我们会说它是 O(1),因为有一个常数 function,例如 g( N)=101,它是 f(N) 的上限。 In this example, you have some bizarre algorithm with oscillating execution times, but you can convey to someone else how much it doesn't slow down for large inputs by simply saying that it's O(1).在此示例中,您有一些执行时间振荡的奇怪算法,但您可以通过简单地说它是 O(1) 来向其他人传达对于大型输入它不会减慢多少。 Neat.整洁的。 Plus we have a way to meaningfully say that this algorithm with trigonometric execution time is more efficient than one with linear complexity O(N).另外,我们有一种方法可以有意义地说,这种具有三角执行时间的算法比具有线性复杂度 O(N) 的算法更有效。 Neat.整洁的。 Notice how it doesn't matter how fast the computer is because we're not measuring in seconds, we're measuring in operations .请注意,计算机的速度有多快并不重要,因为我们不是以秒为单位进行测量,而是以操作为单位进行测量 So you can evaluate the algorithm by hand on paper and it's still O(1) even if it takes you all day.因此,您可以在纸上手动评估算法,即使花费一整天,它仍然是 O(1)。

As for the example in your question, we know it's O(N^2) because there are aN^2+bN+c operations involved for some a, b, c.至于您问题中的示例,我们知道它是 O(N^2),因为某些 a、b、c 涉及 aN^2+bN+c 操作。 It can't be O(1) because no matter what aN+b you pick, I can find a large enough input size N such that your algorithm requires more than aN+b operations.它不可能是 O(1),因为无论您选择什么 aN+b,我都可以找到足够大的输入大小 N,这样您的算法需要的操作不止 aN+b。 On any computer, in any time zone, with any chance of rain outside.在任何计算机上,在任何时区,外面都可能下雨。 Nothing physical effects O(1) versus O(N) versus (N^2). O(1) 对 O(N) 对 (N^2) 没有任何物理影响。 What changes it to O(1) is changing the algorithm itself to the one-liner that I provided above where you just add two numbers and spit out the result no matter what N is.将它更改为 O(1) 的原因是将算法本身更改为我在上面提供的单行代码,您只需添加两个数字并吐出结果,无论 N 是多少。 Let's say for N=10 it takes 4 operations to do both array lookups, the addition, and the variable assignment.假设 N=10 需要 4 次操作来完成数组查找、加法和变量赋值。 If you run it again on the same machine with N=10000000 it's still doing the same 4 operations.如果您在 N=10000000 的同一台机器上再次运行它,它仍然在执行相同的 4 次操作。 The amount of operations required by the algorithm doesn't grow with N. That's why the algorithm is O(1).该算法所需的操作量不会随着 N 的增长而增长。这就是该算法为 O(1) 的原因。

It's why problems like finding a O(NlogN) algorithm to sort an array are math problems and not nano-technology problems.这就是为什么像寻找 O(NlogN) 算法来对数组进行排序这样的问题是数学问题而不是纳米技术问题。 Big-O doesn't even assume you have a computer with electronics. Big-O 甚至不认为您拥有一台带电子设备的计算机。

Hopefully this rant gives you a hint as to what you don't understand so you can do more effective studying for a complete understanding.希望这个咆哮能给你一个关于你明白的提示,这样你就可以更有效地学习以获得完整的理解。 There's no way to cover everything needed in one post here.没有办法在这里的一篇文章中涵盖所有需要的内容。 It was some good soul-searching for me, so thanks.这对我来说是一次很好的灵魂探索,所以谢谢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM