big-O 表示法的问题通常是带有大量假设的非正式(不是说草率)表示法。
首先,Ο 符号1 期望在其括号之间有一个函数,所以像Ο这样的符号>(1) 起初不清楚(因为 1 是数字)。
在某些数学领域习惯用“1”表示函数 f:ℕ→ℕ 定义为 f(n) = 1 ∀n ∊ ℕ。
这只是一个为每个输入返回 1 的函数2。
要考虑的另一点是,经典定义的 Ο 对单变量函数进行操作,为避免歧义,应始终明确写入两个函数的自变量。
然而,这通常不会这样做,因为从上下文中可以清楚地看出我们只处理特定类型的函数。
为了读者的警觉性并以繁琐的符号为代价,我不会删除自变量,从而将 Ο(1) 写为 Ο(1 (n))。
最后,我更喜欢 f(n) ∊ Ο(1(n)) 表示法,而不是使用等号的常见表示法。
我们希望通过符号 f(n) ∊ Ο(1(n)) 来阐明函数的属性 f(n) w.r.t.另一个为每个输入返回 1 的函数。
big-O 表示法是一种简写(就像极限表示法一样),在我们的特定情况下转换为
f(n) ∊ Ο(1(n))
∃N ∊ ℕ: ∀n > N |f(n)| ≤ M · |1(n)| (根据定义)
∃N ∊ ℕ: ∀n > N |f(n)| ≤ M · 1(n) (1(n) 始终为正)
∃N ∊ ℕ: ∀n > N |f(n)| ≤ M · 1 (对于所有 n,1(n) = 1)
∃N ∊ ℕ: ∀n > N |f(n)| ≤ M
所以符号简化为 f(n) 被一个(未指定!)常量 M 限制在绝对值上。
这给我们留下了很多函数,即使给定函数在某一点的值。
例如,即使我们知道 f(2000) = 8,这两个函数 g(n) = 8 cos(n-2000) 和 h(n) = 8 en-2000 两者都在 Ο(1(n)) 但它们在 n = 10000 时的值不同!
big-O 表示法很有用,因为它简化了 事情,但到目前为止,它似乎失败了很多。
缺少的部分是我们正在处理算法及其时间复杂性3,所以我们感兴趣的函数 f 是:
在这个假设下,我们可以看到,如果一个函数是有界的,那么在某个时刻它必须停止增加并无限期地保持在那个值上。
这就是 f(n) ∊ Ο(1(n)) 表示法所表达的:f 是一个常数函数(渐近)。
如果 f 是常数,则 f(n) = c,如果 f(2000) = 8,则 c em> = 8,因此 f(10000) = 8。
Big-O 符号的最佳用法如下:取 Ο 括号之间的函数,乘以常数 c 并将其用于f 的位置。
有时我们甚至不关心常量:Ο(1(n)) 意味着如果我们将 n 加倍输出保持不变,Ο (n) 意味着如果我们加倍 n 输出加倍(n = 2 时 n 为 2),Ο(n2) 表示如果我们将 n 加倍,则输出为四倍(对于 n = 2,n2 为 4)等等。
您的方法存在两个问题:说 T(n) = c * O(1) 是正确的但没用,我们没有取得任何进展,因为我们所说的只是 T(n) 是乘以常数由另一个常数(记住 O(1) 是一个常数函数),因此它是一个常数。
另一个错误是将 O(1) 替换为 n 以获得 c 的值。
O(1) 是一个 set 函数,即使我们把它写成 c' (意思是所有可能的常数),这也不是 n ! n 是输入值,即问题实例的编码大小,而 c' 是一个 任意 常数。
这就是常量函数的全部意义:它们不依赖于输入,如果你愿意,它们在这方面是任意的。
1 不是严格意义上的operator。如果我们将注意力集中在定义在集合 C 和 C 值上的函数上(例如 f ∊ C→ C) 然后 Ο 将 C→C 函数映射到 set 的 C→C 函数(例如 Ο:(C→C)→℘(C→C)) 因此不是来自和去同一个集合的映射。
2 符号故意模糊,让数学家在不同的上下文中使用它;我们将它用于自然值序列,但它可以扩展到任何集合以及返回任何上下文隐含代数结构的“统一性”的含义。
3请注意,运行时是一个非常容易误导的术语!