本文根据算法导论第三章总结,但其中加入了我对本章的一些补充,并且配合算法导论习题进行讲解。
相信本文会让你对渐近记号有更深入地理解。
一、定义介绍
对于某个比较简单的算法,我们有时候确实能够精确地分析出算法的复杂度,比如算法复杂度为5n^2+10n+6,但是事实上并不需要这样,因为当n足够大时,可以忽略掉低阶项和最高次项的系数,因此就引出了“渐近复杂度”,并且用“渐近记号”来表示“渐近复杂度”。
渐近记号包括:
(1)Θ(theta):紧确界。 相当于"="
(2)O (大欧):上界。 相当于"<="
(3)o(小欧):非紧的上界。 相当于"<"
(4)Ω(大omega):下界。 相当于">="
(5)ω(小omega):非紧的下界。 相当于">"
给出这些记号的定义:
对于定义的注意点:
(1)这些定义的前提是f(n)和g(n)是渐近非负的,渐近非负的意思是“当n趋于无穷大时,f(n)和g(n)都非负”。
(2)对于第4和第5条定义,需要注意是对于任意的c。
用集合论来表示这5个符号的关系:
从上面的图可以看出:
(1)如果f(n)=Θ(g(n)),则f(n)=O(g(n))且f(n)=Ω(g(n))。
(2)如果f(n)= o (g(n)),则f(n)=O(g(n))。
(3)如果f(n)=ω(g(n)),则f(n)=Ω(g(n))。
(4)如果f(n)=O(g(n)),则要么是f(n)= o (g(n)),要么是f(n)=Θ(g(n))。
(5)如果 f(n)=Ω(g(n)) ,则要么是f(n)=ω(g(n)),要么是f(n)=Θ(g(n))。
原因其实很简单因为:
(1)如果f(n)=Θ(g(n)),则根据定义一定存在c1,c2,n0,使得对于任意的n>=n0,都有c1g(n)<=f(n)<=c2g(n),因此必定存在
"c=c2,n0,使得对于任意的n>=n0,都有f(n)<=cg(n)"
"c=c1,n0,使得对于任意的n>=n0,都有cg(n)<=f(n)"
(2)如果f(n)= o (g(n)),则根据定义一定对于任意的c,都存在n0,使得任意的n>=n0,都有f(n)<cg(n),因此必定存在“存在c,n0,使得对于任意的n>=n0,都有f(n)<=cg(n)”
(3)如果f(n)= ω (g(n)),则根据定义一定对于任意的c,都存在n0,使得任意的n>=n0,都有cg(n)<f(n),因此必定存在“存在c,n0,使得对于任意的n>=n0,都有cg(n)<=f(n)”
了解了这些定义后,给出一个概念:这些渐近记号表示的都是集合,比如 O (n^2)表示的是一个集合,可以是n,1,n^2等,
因此对于这些渐近记号的使用最准确应该是“f(n)∈ O (g(n))”,但是一般都是写成“f(n)=O(g(n))”。
给出一些例子:
O(n^2)可以是n,2n,1,2n^2等。
Θ(n^2)可以是n^2,3n^2等。
ω(n^2)可以是n^3,n^10等,但不能是n^2。
Ω(n^2)可以是n^2,n^3,n^10等。
o(n^2)可以是n,1,3n等,但不能是n^2。
一般我们对于算法复杂度的描述都是用 O 记号,比如BellmanFord的复杂度为O(VE),表示对于所有的输入,都满足O(VE)。
二、判断两个函数的渐近关系
我们这里给出了很通用的方法,叫做“极限法”。
看到上面的方法,很多人会问“怎么没有 O 和Ω?”,原因很简单,因为如果f(n)=O(g(n)),则要么是f(n)= o (g(n)),要么是f(n)=Θ(g(n))。
stirling公式:
(斯特林公式(Stirling's approximation): 是一条用来取n的阶乘的近似值的数学公式。一般来说,当n很大的时候,n阶乘的计算量十分大,所以斯特林公式十分好用,而且,即使在n很小的时候,斯特林公式的取值已经十分准确。)
还要注意一点:我们在证明时,一般不需要具体指出n0的值,只需要证明一定存在n0即可。(像在算法导论P27页的最后几行中,他给出了很复杂的n0,这不必深究。)
现在开始举例子。
第一个问题来源于算法导论思考题3-1。
第二个问题来源于算法导论3.2-3。
第三个问题来源于算法导论3.2-5。
第四个问题是设计函数以满足一定的条件。
第五个问题也是关于设计一个函数,他是算法导论思考题3-3(b)。
最后还要再举一个算法导论思考题3-4,因为这道题能够更清晰地理清概念。