渐近函数是什么?无论如何,渐近线是什么?
给定一个函数f(n),该函数描述当算法应用于大小为n的输入时算法消耗的资源量(CPU时间,RAM,磁盘空间等),我们最多定义三个渐近符号来描述其性能。大n。
渐近线(或渐近函数)只是g(n)的其他某些函数(或关系),随着n越来越大,f(n)越来越接近,但从未达到。讨论渐近函数的好处是,即使f(n)的表达式极其复杂,它们通常也更易于讨论。渐近函数用作限制 f(n)上下的边界符号的一部分。
(注意:从这里使用的意义上来说,渐进函数仅在校正了一些恒定的非零因子后才接近原始函数,因为所有三个big-O /Θ/Ω表示法都忽略了它们的考虑。)
三种渐近边界符号是什么?它们有何不同?
这三种符号的用法如下:
f(n)= O(g(n))
其中f(n)是感兴趣的函数,而g(n)是您尝试近似f(n)的其他一些渐近函数。严格意义上,这不应该视为等式,而应正式说明f(n)相对于n与g(n)相比增长多快,随着n变大。纯粹主义者通常会使用替代符号f(n)∈O(g(n))来强调符号O(g(n))实际上是具有相同增长率的函数的整个族。
Big-ϴ(θ)表示在f(n)增长到一个恒定因子之前相等(稍后会详细介绍)。它的行为类似于操作员的增长率。=
Big-O表示法描述了f(n)增长的上限。它的行为类似于操作员的增长率。≤
Big-Ω(Omega)表示随着f(n)的增长而下界。它的行为类似于操作员的增长率。≥
还有许多其他渐近符号,但是它们在计算机科学文献中的出现频率并不高。
大O表示法及其类似方法通常是比较时间复杂度的一种方法。
什么是时间复杂度?
时间复杂度是时间T(n)的一个奇特术语,即算法根据其输入大小n执行函数所花费的时间。这可以通过实时量(例如秒),CPU指令数等来度量。通常假设该算法将在您的日常von Neumann体系结构计算机上运行。但是,当然,您可以使用时间复杂度来谈论更多奇异的计算系统,但情况可能有所不同!
使用Big-O表示法谈论空间复杂性也是很常见的。空间复杂度是完成算法所需的内存(存储)量,可能是RAM,磁盘等。
可能是一种算法较慢但使用较少的内存,而另一种算法较快但使用更多的内存。如果资源受到不同限制,则每种方法在不同情况下可能更合适。例如,嵌入式处理器可能具有有限的内存并倾向于使用较慢的算法,而数据中心中的服务器可能具有大量的内存并倾向于使用较快的算法。
计算大ϴ
计算算法的大重点是一个可以填满一本小本教科书或大约半学期的本科课程的主题:本节将介绍基础知识。
给定伪代码中的函数f(n):
int f(n) {
int x = 0;
for (int i = 1 to n) {
for (int j = 1 to n) {
++x;
}
}
return x;
}
时间的复杂度是多少?
外循环运行n次。每次外循环运行一次,内循环运行n次。这将运行时间设为T(n)= n 2。
考虑第二个功能:
int g(n) {
int x = 0;
for (int k = 1 to 2) {
for (int i = 1 to n) {
for (int j = 1 to n) {
++x;
}
}
}
return x;
}
外循环运行两次。中间循环运行n次。每次中间循环运行一次,内部循环运行n次。这将运行时间设为T(n)= 2n 2。
现在的问题是,两个函数的渐近运行时间是多少?
要计算这一点,我们执行两个步骤:
- 删除常量。随着算法由于输入而增加时间,其他术语主导了运行时间,使其变得不重要。
- 除去除最大期限外的所有词语。随着n达到无穷大,n 2迅速超过n。
他们在这里的重点是重点词,并简化为这些词。
T(N)= N 2 ∈Θ(N 2)
T(N)= 2 2 ∈Θ(N 2)
如果我们有另一个具有多个术语的算法,则可以使用相同的规则对其进行简化:
T(n)= 2n 2 + 4n + 7∈ϴ(n 2)
所有这些算法的关键是我们关注最大的项并删除常量。我们不是在看实际的运行时间,而是相对的复杂性。
计算Big-Ω和Big-O
首先要注意的是,在非正式文学中,“ Big-O”通常被视为Big-Θ 的同义词,这也许是因为希腊字母的输入方式比较棘手。因此,如果突然有人要求您提供算法的Big-O,他们可能会想要Big-Θ。
现在,如果您确实确实想按照前面定义的形式来计算Big-Ω和Big-O ,则会遇到一个主要问题:对于任何给定的函数,都有无限多个Big-Ω和Big-O描述!这就像问小于或等于42的数字是多少。有很多可能性。
对于具有T(n)∈ϴ(n 2)的算法,以下任何形式上正确有效的陈述:
- T(n)∈O(n 2)
- T(n)∈O(n 3)
- T(n)∈O(n 5)
- T(n)∈O(n 12345 ×e n)
- T(n)∈Ω(n 2)
- T(n)∈Ω(n)
- T(n)∈Ω(log(n))
- T(n)∈Ω(log(log(n)))
- T(n)∈Ω(1)
但是陈述T(n)∈O(n)或T(n)∈Ω(n 3)是不正确的。
什么是相对复杂度?有哪些类别的算法?
如果我们比较两种不同的算法,随着输入到无穷大,它们的复杂性通常会增加。如果我们查看不同类型的算法,它们可能会保持相对不变(例如,相差一个常数)或可能会有很大差异。这就是执行Big-O分析的原因:确定算法在大输入下是否会合理执行。
算法类别细分如下:
Θ(1)-恒定 例如,选择列表中的第一个数字将始终花费相同的时间。
Θ(n)-线性 例如,迭代列表将始终花费与列表大小n成正比的时间。
Θ(log(n))-对数(基数通常无关紧要)。在每个步骤中划分输入空间的算法(例如二进制搜索)就是示例。
Θ(n×log(n))-线性乘以对数(“ linearithmic”)。这些算法通常在分割和征服(log(n))的同时仍迭代(n)所有输入。许多流行的排序算法(合并排序,Timsort)都属于此类。
Θ(n m)-多项式(n升为任意常数m)。这是一个非常常见的复杂性类,通常在嵌套循环中找到。
Θ(m n)-指数(任何常数m升至n)。许多递归和图形算法都属于此类。
Θ(n!)-阶乘 某些图形和组合算法是阶乘复杂性。
这与最佳/平均/最坏情况有关吗?
不可以 。Big-O及其表示法家族谈论一种特定的数学函数。它们是用来帮助表征算法效率的数学工具,但是最佳/平均/最坏情况的概念与此处所述的增长率理论无关。
要谈论一种算法的Big-O,必须致力于一种算法的特定数学模型,该模型仅具有一个参数n
,无论用什么意义,该参数都应描述输入的“大小”。但是在现实世界中,输入的结构不仅仅是长度。如果这是一个排序算法,我可以养活的字符串"abcdef"
,"fedcba"
或"dbafce"
。它们的长度均为6,但是其中一个已经排序,一个已经反转,最后一个只是一个随机的杂物。如果输入已经排序,则某些排序算法(例如Timsort)会更好地工作。但是,如何将这种不均匀性纳入数学模型呢?
典型的方法是简单地假设输入来自某种随机的概率分布。然后,您对长度为的所有输入求平均算法的复杂度n
。这为您提供了算法的平均情况复杂度模型。在这里,您可以像往常一样使用Big-O /Θ/Ω表示法来描述平均情况下的行为。
但是,如果您担心拒绝服务攻击,那么您可能会更加悲观。在这种情况下,可以更安全地假设唯一的输入是那些会给您的算法带来最大痛苦的输入。这为您提供了算法的最坏情况复杂度模型。之后,您可以讨论最坏情况模型的Big-O /Θ/Ω等。
同样,您也可以将兴趣完全集中在算法遇到最少麻烦的输入上,以得出最佳情况模型,然后查看Big-O /Θ/Ω等。