我很难理解大 O 时间复杂度。
大 O 的正式定义:
f(n) = O(g(n))
表示存在正常数c
和k
,使得对于所有的n ≥ k
,都有0 ≤ f(n) ≤ cg(n)
。其中c
和k
的值必须固定为函数f
,并且不能依赖于n
。
而插入排序的最坏时间复杂度是 O(n^2)
。
我想了解在插入排序中,f(n)
、g(n)
、c
和 k
分别代表什么意义。
我很难理解大 O 时间复杂度。
大 O 的正式定义:
f(n) = O(g(n))
表示存在正常数c
和k
,使得对于所有的n ≥ k
,都有0 ≤ f(n) ≤ cg(n)
。其中c
和k
的值必须固定为函数f
,并且不能依赖于n
。
而插入排序的最坏时间复杂度是 O(n^2)
。
我想了解在插入排序中,f(n)
、g(n)
、c
和 k
分别代表什么意义。
要将算法形式化以便可以正式应用大O,这并不容易,因为它是一个数学概念,不容易转化成算法。通常,您会根据输入的大小来测量执行操作所需的“计算步骤”数量。
f
是衡量算法执行多少计算步骤的函数。n
是输入的大小,例如对于像[4, 2, 9, 8, 2]
这样的列表,n
为5
。g
是您要针对进行测量的函数,因此,如果您检查O(n^2)
,则g = n^2
。c
和 k
在很大程度上取决于具体的算法和f
的实际样子。正式定义一个算法最大的问题在于您无法准确地告诉程序执行了多少计算步骤。我们假设有以下Java代码:
public static void printAllEven(int n) {
for (int i = 0; i < n; i++) {
if (i % 2 == 0) {
System.out.println(i);
}
}
}
for (int i = 0; i < count; i++)
呢?这是在循环期间执行的多个语句。那么,i % 2
呢?我们可以假设这是一个“单个操作”吗?在哪个层次上,一个CPU周期?一条汇编线?println(i)
呢?它需要多少计算步骤,1、5或者200?println(i)
被调用的频率。n / 2
次(因为在0
和n
之间有这么多偶数)。n * A + n * B + n/2 * C
但是由于常量在c中并没有真正发挥任何作用(它们会消失),因此我们也可以忽略它并简化问题。
现在您需要证明例如n/2
在O(n^2)
中,通过这样做,您也将得到c和k的具体数字。例如:
n / 2 <= n <= 1 * n^2 // for all n >= 0
c = 1
和k = 0
就证明了这个命题。其他的c
和k
的值也可以,例如:n / 2 <= 100 * n <= 5 * n^2 // for all n >= 20
在这里,我们选择了c = 5
和k = 20
。
您也可以使用完整公式玩同样的游戏,得到类似的结果。
n * A + n * B + n/2 * C
<= n * (A + B + C)
= D * n
<= D * n^2 // for all n > 0
当 c = D
且 k = 0
时,如你所见,这些常量并不发挥任何作用,因为这些常量会在 c
中消失。