由第二章中我们得知,算法的时间复杂度只与算法的高阶项有关。当输入规模n足够大时,高阶项的花费远超过低阶项。因此在计算算法的运行时间时,尽管可以求出精确的运行时间,但是并不值得我们这么做。
在n很大的情况下,我们更感兴趣的是算法的渐进效率,即,当输入规模无限增加时,在极限中,算法的运行时间如何随着输入规模的变大而变大。
这一章首先介绍了几个“渐进记号”,其中,我们见过Θ记号。然后,我们简单介绍几个函数以及性质。
一、渐进记号
我们用渐进记号来刻画算法的运行时间,以便于方便的描述最坏运行时间函数T(n)。
本章主要介绍Θ、O、Ω记号,以及相对应的θ、o、ω记号(注意大小写)。
上图给出了f(n)与g(n)的关系。标出的n0是最小的可能值。任何大于n0的值都有效。在图一中,表示Θ记号,即将f(n)限制在c1g(n)与c2g(n)之间,给出了f(n)的上下界。图二中表示O记号,给出函数f(n)的上界。图三中表示Ω记号,给出f(n)的下界
Θ记号
由第二章,我们知道插入排序的最坏时间是T(n)=Θ(n²)。我们给出这个记号的定义:对于一个给定的函数g(n),Θ(g(n))表示以下函数的集合:
θ(g(n))={f(n):存在常量c1、c2 和 n0,使得对所有n≥n0,有0≤c1g(n)≤f(n)≤c2g(n)}(在集合中,冒号的含义是“使得”)
通俗的说,就是Θ(g(n))表示满足0≤c1g(n)≤f(n)≤c2g(n)的f(n)函数的集合。因为Θ(g(n))是一个集合,可以记作“f(n)∈Θ(g(n))”,以指出f(n)是Θ(g(n))集合中的一员。但是我们通常记作“f(n)=Θ(g(n))”。
由Θ(g(n))的定义可知,每个成员f(n)∈Θ(g(n))均渐进非负。因此,g(n)本身也是渐进非负,否则集合Θ(g(n))为空。我们假设在Θ记号内的每个函数都是渐进非负的。这个假设对其他记号也成立。
O记号
Θ记号给出了函数的上界和下界,而当只有一个渐进上界时使用O记号。对于一个给定的函数g(n),O(g(n))表示以下函数的集合:
O(g(n))={f(n):存在常量c和 n0,使得对所有n≥n0,有0≤f(n)≤cg(n)}
O记号给出了函数的一个在常量因子的上界,在衡量算法的时间复杂度时,我们通常比较算法的最坏时间,所以多数情况下时间复杂度用该记号表示,被称为大O表示法。
我们记f(n)=O(g(n))以指出f(n)是集合O(g(n))的成员。但是注意,f(n)=Θ(g(n))包含着f(n)=O(g(n))。
Ω记号
与O记号相反,当只有一个渐进下届时使用Ω记号,相应的定义为:
Ω(g(n))={f(n):存在常量c和 n0,使得对所有n≥n0,有0≤cg(n)≤f(n)}
Ω记号通常表示最好的情况,例如,插入排序的最好运行时间为Ω(n)。
等式和不等式中的渐进记号
当渐进记号独立于等式或不等式的右边时,我们已经定义等号意味着指出了集合的成员关系。如对n= O(n²),我们是指n∈O(n²)。然而,当渐进记号出现在某个公式中,我们通常解释为我们所不关注名称的匿名函数。
例如,在公式2n²+3n+1=2n²+Θ(n)指的是2n²+3n+1=2n²+f(n)。f(n)是集合Θ(n)中的某个函数。安好这种方式可以帮助消除一个等式中无关紧要的细节与混乱。使得等式更清晰,方便我们抓住重点。例如,在第二章中,归并排序的最坏运行时间我们表示为递归式T(n)=2T(n/2)+Θ(n)。如果只对T(n)的渐进行为感兴趣,那么没有必要把所有低阶项都准确说出来,用包含在Θ(n)中的匿名函数代指他们。
在某些例子中,渐进记号也出现在等式的左边,如:2n²+Θ(n)=Θ(n²),这该如何解释?
我们将其解释为:无论怎样选择等号左边的匿名函数,总有一种办法来选择等号右边的匿名函数使得等式成立。也就是说,对任意函数f(n)∈Θ(n),存在某个函数g(n)∈Θ(n²),使得对所有的n,有2n²+f(n)=g(n)。可以看出,等式左边提供了更多的细节,等式右边更粗糙。当我们把很多个这样的关系链在一起,你就会看的更明白:
2n²+3n+1=2n²+Θ(n)=Θ(n²)
看到了吧,最左边的式子提供了很多具体细节,他将二次项、一次项、常数项都清楚的指出来。而当到第二个式子时,3n+1被泛化成了Θ(n),而在最右边,所有的项都被泛化成最高阶项的集合Θ(n²)。
o记号
由大O记号提供的渐进上界可能是渐进紧确的也可能不是渐进紧确的。例如,界2n²=O(n²)时渐进紧确的,而界2n=O(n²)就不是。当出现这种情况时,我们用o记号来表示一个非渐进紧确的上界。o(g(n))定义为:
o(g(n))={f(n):对任意正常量c>0,存在常量n0>0,使得对所有n>=n0,有0<=f(n)<=cg(n)}
例如2n=o(n²),但是2n²≠o(n²)
从定义上来看,O与o类似,区别是在f(n)=O(g(n))中,界0<=f(n)<=cg(n)对某个常量c>0成立,而在f(n)=o(g(n))中,界0<=f(n)<cg(n)对所有c>0都成立。
在o记号中,当n趋于无穷时,函数f(n)相较与g(n)变得微不足道了,即
limn→∞f(n)/g(n)=0
ω记号
ω与Ω记号的关系和o与O记号关系类似。我们使用ω来表示一个渐进非紧确的下界。定义为:
ω(g(n))={f(n):对任意正常量c>0,存在常量n0>0,使得对所有n>=n0,有0<=cg(n)<f(n)}
他的另一种定义方式是:
f(n)∈ω(g(n))当且仅当g(n)∈o(f(n))
例如:n²/2=ω(n),但是n²/2≠ω(n²)。关系f(n)=ω(g(n))蕴含着
limn→∞f(n)/g(n)=∞
也就是说,如果这个极限存在,当n趋于∞时,f(n)相对于g(n)来说变得任意大了。
各种函数性质
实数的许多关系性质也适用于渐进比较。下面假定f(n)和g(n)渐进为正。
传递性
f(n)=Θ(g(n))且g(n)=Θ(h(n)),则蕴含着f(n)=Θ(h(n))
f(n)=O(g(n))且g(n)=O(h(n)),则蕴含着f(n)=O(h(n))
f(n)=Ω(g(n))且g(n)=Ω(h(n)),则蕴含着f(n)=Ω(h(n))
f(n)=o(g(n))且g(n)=o(h(n)),则蕴含着f(n)=o(h(n))
f(n)=ω(g(n))且g(n)=ω(h(n)),则蕴含着f(n)=ω(h(n))
自反性
f(n)=Θ(f(n))
f(n)=O(f(n))
f(n)=Ω(f(n))
对称性
f(n)=Θ(g(n))当且仅当g(n)=Θ(f(n))
转置对称性
f(n)=O(g(n))当且仅当g(n)=Ω(f(n))
f(n)=o(g(n))当且仅当g(n)=ω(f(n))
二、标准记号与常用函数
本书里用到的大多数数学函数与记号在学习生涯中基本都学过,这里不再赘述,只简单介绍一下斐波那契数列。
斐波那契数列
按照下面的递归式定义斐波那契数列:
F0=0
F1=1
F2=F0+F1=1
F3=F2+F1=2
…
Fn=Fn-1 + Fn-2,n大于等于2
即从第三项开始,每一项都是前两项的和。
斐波那契数列的通项公式为:
扩展:通项公式推导(来源:百度百科——斐波那契数列)
利用特征方程(线性代数解法)
线性递推数列的特征方程为:
x²=x+1
解得
则
解得
(完)