《算法导论(原书第3版)》一3.1 渐近记号

简介: 本节书摘来自华章出版社《算法导论(原书第3版)》一 书中的第3章,第3.1节,作者:(美)Thomas H.Cormen,Charles E.Leiserson,Ronald L.Rivest,Clifford Stein,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

3.1 渐近记号

用来描述算法渐近运行时间的记号根据定义域为自然数集N={0,1,2,…}的函数来定义。这样的记号对描述最坏情况运行时间函数T(n)是方便的,因为该函数通常只定义在整数输入规模上。然而,我们发现有时按各种方式活用渐近记号是方便的。例如,我们可以扩展该记号到实数域或者选择性地限制其到自然数的一个子集。
43然而,我们应该确保能理解该记号的精确含义,以便在活用时不会误用它。本节将定义一些基本的渐近记号,并介绍一些常见的活用法。

渐近记号、函数与运行时间

正如我们写插入排序的最坏情况运行时间为Θ(n2)时那样,我们将主要使用渐近记号来描述算法的运行时间。然而,渐近记号实际上应用于函数。回顾一下,我们曾把插入排序的最坏情况运行时间刻画为an2+bn+c,其中a、b和c是常量。通过把插入排序的运行时间写成Θ(n2),我们除去了该函数的某些细节。因为渐近记号适用于函数,我们所写成的Θ(n2)就是函数an2+bn+c,所以上述情况碰巧刻画了插入排序的最坏情况运行时间。

本书中对其使用渐近记号的函数通常刻画算法的运行时间。但是渐近记号也可以适用于刻画算法的某个其他方面(例如,算法使用的空间数量)的函数,甚至可以适用于和算法没有任何关系的函数。

即使我们使用渐近记号来刻画算法的运行时间,我们也需要了解意指哪个运行时间。有时我们对最坏情况运行时间感兴趣。然而,我们常常希望刻画任何输入的运行时间。换句话说,我们常常希望做出一种综合性地覆盖所有输入而不仅仅是最坏情况的陈述。我们将看到完全适合刻画任何输入的运行时间的渐近记号。

   在集合记号中,冒号意指“使得”。

Θ记号

在第2章,我们发现插入排序的最坏情况运行时间为T(n)=Θ(n2)。让我们来定义这个记号意指什么。对一个给定的函数g(n),用Θ(g(n))来表示以下函数的集合:

44Θ(g(n))={f(n):存在正常量c1、c2和n0,使得对所有n≥n0,有0≤c1g(n)≤f(n)≤c2g(n)}

若存在正常量c1和c2,使得对于足够大的n,函数f(n)能“夹入”c1g(n)与c2g(n)之间,则f(n)属于集合Θ(g(n))。因为Θ(g(n))是一个集合,所以可以记“f(n)∈Θ(g(n))”,以指出f(n)是Θ(g(n))的成员。作为替代,我们通常记“f(n)=Θ(g(n))”以表达相同的概念。因为我们按这种方式活用了等式,所以你可能感到困惑,但是在本节的后面我们将看到这样做有其好处。

图3-1(a)给出了函数f(n)与g(n)的一幅直观画面,其中f(n)=Θ(g(n))。对在n0及其右边n的所有值,f(n)的值位于或高于c1g(n)且位于或低于c2g(n)。换句话说,对所有n≥n0,函数f(n)在一个常量因子内等于g(n)。我们称g(n)是f(n)的一个渐近紧确界(asymptotically tight bound)。

screenshot

图3-1 Θ、O和Ω记号的图例。在每个部分,标出的n0的值是最小的可能值,任何更大的值也将有效。(a)Θ记号限制一个函数在常量因子内。如果存在正常量n0、c1和c2,使得在n0及其右边,f(n)的值总位于c1g(n)与c2g(n)之间或等于它们,那么记f(n)=Θ(g(n))。(b)O记号为函数给出一个在常量因子内的上界。如果存在正常量n0和c,使得在n0及其右边,f(n)的值总小于或等于cg(n),那么记f(n)=O(g(n))。(c)Ω记号为函数给出一个在常量因子内的下界。如果存在正常量n0和c,使得在n0及其右边,f(n)的值总大于或等于cg(n),那么记f(n)=Ω(g(n))

Θ(g(n))的定义要求每个成员f(n)∈Θ(g(n))均渐近非负,即当n足够大时,f(n)非负。(渐近正函数就是对所有足够大的n均为正的函数。)因此,函数g(n)本身必为渐近非负,否则集合Θ(g(n))为空。所以我们假设用在Θ记号中的每个函数均渐近非负。这个假设对本章定义的其他渐近记号也成立。
45

在第2章,我们介绍了Θ记号的一种非形式化的概念,相当于扔掉低阶项并忽略最高阶项前的系数。让我们通过使用形式化定义证明12n2-3n=Θ(n2)来简要地证实这种直觉。为此,我们必须确定正常量c1、c2和n0,使得对所有n≥n0,有:
c1n2≤12n2-3n≤c2n2

用n2除上式得:
c1≤12-3n≤c2

通过选择任何常量c2≥1/2,可以使右边的不等式对任何n≥1的值成立。同样,通过选择任何常量c1≤1/14,可以使左边的不等式对任何n≥7的值成立。因此,通过选择c1=1/14,c2=1/2且n0=7,可以证明12n2-3n=Θ(n2)。当然,还存在对这些常量的其他选择,但是重要的是存在某个选择。要注意的是,这些常量依赖于函数12n2-3n;属于Θ(n2)的不同函数通常需要不同的常量。

我们还可以使用形式化定义来证明6n3≠Θ(n2)。采用反证法,假设存在c2和n0,使得对所有n≥n0,有6n3≤c2n2。然而用n2除该式,得n≤c2/6,因为c2为常量,所以对任意大的n,该不等式不可能成立。

直觉上,一个渐近正函数的低阶项在确定渐近确界时可以被忽略,因为对大的n,它们是无足轻重的。当n较大时,即使最高阶项的一个很小的部分都足以支配所有低阶项。因此,将c1置为稍小于最高阶项系数的值并将c2置为稍大于最高阶项系数的值能使Θ记号定义中的不等式得到满足。最高阶项系数同样可以被忽略,因为它仅仅根据一个等于该系数的常量因子来改变c1和c2。

作为一个例子,考虑任意二次函数f(n)=an2+bn+c,其中a、b和c均为常量且a>0。扔掉低阶项并忽略常量后得f(n)=Θ(n2)。为了形式化地证明相同的结论,我们取常量c1=a/4,c2=7a/4且n0=2·max(b/a,c/a)。可以证明对所有n≥n0,有0≤c1n2≤an2+bn+c≤c2n2。一般来说,对任意多项式p(n)=∑di=0aini,其中ai为常量且ad>0,我们有p(n)=Θ(nd)(参见思考题3-1)。

因为任意常量是一个0阶多项式,所以可以把任意常量函数表示成Θ(n0)或Θ(1)。
46然而,后一种记号是一种轻微的活用,因为该表达式并未指出什么变量趋于无穷。我们将经常使用记号Θ(1)来意指一个常量或者关于某个变量的一个常量函数。

   真正的问题是通常的函数记号没有区分函数与函数值。在λ演算中,函数的参数被清楚地说明:函数n2可被写成λn.n2,或者甚至写成λr.r2。然而,采用一种更严格的记号将使代数操作复杂化,所以我们选择容忍这种活用。

O记号

Θ记号渐近地给出一个函数的上界和下界。当只有一个渐近上界时,使用O记号。对于给定的函数g(n),用O(g(n))(读作“大Og(n)”,有时仅读作“Og(n)”)来表示以下函数的集合:
O(g(n))={f(n):存在正常量c和n0,使得对所有n≥n0,有0≤f(n)≤cg(n)}

我们使用O记号来给出函数的一个在常量因子内的上界。图3-1(b)展示了O记号背后的直觉知识。对在n0及其右边的所有值n,函数f(n)的值总小于或等于cg(n)。

我们记f(n)=O(g(n))以指出函数f(n)是集合O(g(n))的成员。注意,f(n)=Θ(g(n))蕴涵着f(n)=O(g(n)),因为Θ记号是一个比O记号更强的概念。按集合论中的写法,我们有Θ(g(n))O(g(n))。因此,关于任意二次函数an2+bn+c,其中a>0,在Θ(n2)中的证明也证明了任意这样的二次函数在O(n2)中。也许更令人惊奇的是当a>0时,任意线性函数an+b也在O(n2)中,通过取c=a+b和n0=max(1,-b/a),可以很容易证明这个结论。

如果你以前见过O记号,你会发现我们这样书写(如n=O(n2))很奇怪。在文献中,有时我们发现O记号非形式化地描述渐近确界,即已经使用Θ记号定义的东西。然而,本书中当书写f(n)=O(g(n))时,我们仅仅要求g(n)的某个常量倍数是f(n)的渐近上界,而不要求它是一个多么紧确的上界。在算法文献中,标准的做法是区分渐近上界与渐近确界。

使用O记号,我们常常可以仅仅通过检查算法的总体结构来描述算法的运行时间。例如,第2章中插入排序算法的双重嵌套循环结构对最坏情况运行时间立即产生一个O(n2)的上界:内层循环每次迭代的代价以O(1)(常量)为上界,下标i和j均最多为n,
47对于n2个i和j值对的每一对,内循环最多执行一次。

既然O记号描述上界,那么当用它来限制算法的最坏情况运行时间时,关于算法在每个输入上的运行时间,我们也有一个界,这就是前面讨论的综合性陈述。因此,对插入排序的最坏情况运行时间的界O(n2)也适用于该算法对每个输入的运行时间。然而,对插入排序的最坏情况运行时间的界Θ(n2)并未暗示插入排序对每个输入的运行时间的界也是Θ(n2)。例如,我们在第2章曾看到当输入已排好序时,插入排序的运行时间为Θ(n)。

从技术上看,称插入排序的运行时间为O(n2)有点不合适,因为对给定的n,实际的运行时间是变化的,依赖于规模为n的特定输入。当我们说“运行时间为O(n2)”时,意指存在一个O(n2)的函数f(n),使得对n的任意值,不管选择什么特定的规模为n的输入,其运行时间的上界都是f(n)。这也就是说最坏情况运行时间为O(n2)。

Ω记号

正如O记号提供了一个函数的渐近上界,Ω记号提供了渐近下界。对于给定的函数g(n),用Ω(g(n))(读作“大Ωg(n)”,有时仅读作“Ωg(n)”)来表示以下函数的集合:
Ω(g(n))={f(n):存在正常量c和n0,使得对所有n≥n0,有0≤cg(n)≤f(n)}

图3-1(c)给出了Ω记号的直观解释。对在n0及其右边的所有值n,f(n)的值总大于或等于cg(n)。 

根据目前所看到的这些渐近记号的定义,容易证明以下重要定理(参见练习3.1-5)。

定理3.1 对任意两个函数f(n)和g(n),我们有f(n)=Θ(g(n)),当且仅当f(n)=O(g(n))且f(n)=Ω(g(n))。

作为应用本定理的一个例子,关于对任意常量a、b和c,其中a>0,有an2+bn+c=Θ(n2)的证明直接蕴涵an2+bn+c=Ω(n2)和an2+bn+c=O(n2)。实际上不是像该例子中所做的,应用定理3.1从渐近确界获得渐近上界和下界,而是通常用它从渐近上界和下界来证明渐近确界。
48

当称一个算法的运行时间(无修饰语)为Ω(g(n))时,我们意指对每个n值,不管选择什么特定的规模为n的输入,只要n足够大,对那个输入的运行时间至少是g(n)的常量倍。等价地,我们再对一个算法的最好情况运行时间给出一个下界。例如,插入排序的最好情况运行时间为Ω(n),这蕴涵着插入排序的运行时间为Ω(n)。

所以插入排序的运行时间介于Ω(n)和O(n2),因为它落入n的线性函数与n的二次函数之间的任何地方。而且,这两个界是尽可能渐近地紧确的:例如,插入排序的运行时间不是Ω(n2),因为存在一个输入(例如,当输入已排好序时),对该输入,插入排序在Θ(n)时间内运行。然而,这与称插入排序的最坏情况运行时间为Ω(n2)并不矛盾,因为存在一个输入,使得该算法需要Ω(n2)的时间。

等式和不等式中的渐近记号

我们已经看到渐近记号可以如何用于数学公式中。例如,在介绍O记号时,记“n=O(n2)”。我们还可能写过2n2+3n+1=2n2+Θ(n)。如何解释这样的公式呢?

当渐近记号独立于等式(或不等式)的右边(即不在一个更大的公式内)时,如在n=O(n2)中,我们已经定义等号意指集合的成员关系:n∈O(n2)。然而,一般来说,当渐近记号出现在某个公式中时,我们将其解释为代表某个我们不关注名称的匿名函数。例如,公式2n2+3n+1=2n2+Θ(n)意指2n2+3n+1=2n2+f(n),其中f(n)是集合Θ(n)中的某个函数。在这个例子中,假设f(n)=3n+1,该函数确实在Θ(n)中。

按这种方式使用渐近记号可以帮助消除一个等式中无关紧要的细节与混乱。例如,在第2章中,我们把归并排序的最坏情况运行时间表示为递归式
T(n)=2T(n/2)+Θ(n)

如果只对T(n)的渐近行为感兴趣,那么没有必要准确说明所有低阶项,它们都被理解为包含在由项Θ(n)表示的匿名函数中。

一个表达式中匿名函数的数目可以理解为等于渐近记号出现的次数。例如,在表达式∑ni=1O(i)中,只有一个匿名函数(一个i的函数)。
49因此,这个表达式不同于O(1)+O(2)+…+O(n),实际上后者没有一个清晰的解释。

在某些例子中,渐近记号出现在等式的左边,例如
2n2+Θ(n)=Θ(n2)

我们使用以下规则来解释这种等式:无论怎样选择等号左边的匿名函数,总有一种办法来选择等号右边的匿名函数使等式成立。因此,我们的例子意指对任意函数f(n)∈Θ(n),存在某个函数g(n)∈Θ(n2),使得对所有的n,有2n2+f(n)=g(n)。换句话说,等式右边比左边提供的细节更粗糙。

我们可以将许多这样的关系链在一起,例如
2n2+3n+1=2n2+Θ(n)=Θ(n2)

可以用上述规则分别解释每个等式。第一个等式表明存在某个函数f(n)∈Θ(n),使得对所有的n,有2n2+3n+1=2n2+f(n)。第二个等式表明对任意函数g(n)∈Θ(n)(如刚刚提到的f(n)),存在某个函数h(n)∈Θ(n2),使得对所有的n,有2n2+g(n)=h(n)。注意,这种解释蕴涵着2n2+3n+1=Θ(n2),这就是等式链直观上提供给我们的东西。

o记号

由O记号提供的渐近上界可能是也可能不是渐近紧确的。界2n2=O(n2)是渐近紧确的,但是界2n=O(n2)却不是。我们使用o记号来表示一个非渐近紧确的上界。形式化地定义o(g(n))(读作“小og(n)”)为以下集合:
o(g(n))={f(n):对任意正常量c>0,存在常量n0>0,使得对所有n≥n0,有0≤f(n)

例如,2n=o(n2),但是2n2≠o(n2)。

O记号与o记号的定义类似。主要的区别是在f(n)=O(g(n))中,界0≤f(n)≤cg(n)对某个常量c>0成立,但在f(n)=o(g(n))中,界0≤f(n)0成立。直观上,在o记号中,当n趋于无穷时,函数f(n)相对于g(n)来说变得微不足道了,
50即
limn→∞f(n)g(n)=0(3.1)

有些学者使用这个极限作为o记号的定义;本书中的定义还限定匿名函数是渐近非负的。

ω记号

ω记号与Ω记号的关系类似于o记号与O记号的关系。我们使用ω记号来表示一个非渐近紧确的下界。定义它的一种方式是:
f(n)∈ω(g(n))当且仅当g(n)∈o(f(n))

然而,我们形式化地定义ω(g(n))(读作“小ωg(n)”)为以下集合:
ω(g(n))={f(n):对任意正常量c>0,存在常量n0>0,使得对所有n≥n0,有0≤cg(n)<f(n)}

例如,n2/2=ω(n),但是n2/2≠ω(n2)。关系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))

51f(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))

因为这些性质对渐近记号成立,所以可以在两个函数f与g的渐近比较和两个实数a与b的比较之间做一种类比。
f(n)=O(g(n))类似于a≤b

f(n)=Ω(g(n))类似于a≥b

f(n)=Θ(g(n))类似于a=b

f(n)=o(g(n))类似于a

f(n)=ω(g(n))类似于a>b

若f(n)=o(g(n)),则称f(n)渐近小于g(n);若f(n)=ω(g(n)),则称f(n)渐近大于g(n)。

然而,实数的下列性质不能携带到渐近记号:

三分性 对任意两个实数a和b,下列三种情况恰有一种必须成立:ab。

虽然任意两个实数都可以进行比较,但不是所有函数都可渐近比较。也就是说,对两个函数f(n)和g(n),也许f(n)=O(g(n))和f(n)=Ω(g(n))都不成立。例如,我们不能使用渐近记号来比较函数n和n1+sin n,因为n1+sin n中的幂值在0与2之间摆动,取介于两者之间的所有值。

练习

3.1-1 假设f(n)与g(n)都是渐近非负函数。使用Θ记号的基本定义来证明max(f(n),g(n))=Θ(f(n)+g(n))。

3.1-2 证明:对任意实常量a和b,其中b>0,有

52(n+a)b=Θ(nb)(3.2)

3.1-3 解释为什么“算法A的运行时间至少是O(n2)”这一表述是无意义的。

3.1-4 2n+1=O(2n)成立吗?22n=O(2n)成立吗?

3.1-5 证明定理3.1。

3.1-6 证明:一个算法的运行时间为Θ(g(n))当且仅当其最坏情况运行时间为O(g(n)),且其最好情况运行时间为Ω(g(n))。

3.1-7 证明:o(g(n))∩ω(g(n))为空集。

3.1-8 可以扩展我们的记号到有两个参数n和m的情形,其中的n和m可以按不同速率独立地趋于无穷。对于给定的函数g(n,m),用O(g(n,m))来表示以下函数集:
O(g(n,m))={f(n,m):存在正常量c、n0和m0,使得对所有n≥n0或m≥m0,

有0≤f(n,m)≤cg(n,m)}

对Ω(g(n,m))和Θ(g(n,m))给出相应的定义。

相关文章
|
算法 机器学习/深度学习
算法导论------渐近记号Θ、Ο、o、Ω、ω详解
目录: 1.渐近精确界记号:Θ(big-theta) 2.渐近上界记号 :O(big-oh) 3.渐近下界记号 :Ω(big-omege) 4.非渐近紧确上界:o(小-oh) 5.非渐近紧确下界:ω(小-omege) 6.
7110 0
|
8天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
26天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于MSER和HOG特征提取的SVM交通标志检测和识别算法matlab仿真
### 算法简介 1. **算法运行效果图预览**:展示算法效果,完整程序运行后无水印。 2. **算法运行软件版本**:Matlab 2017b。 3. **部分核心程序**:完整版代码包含中文注释及操作步骤视频。 4. **算法理论概述**: - **MSER**:用于检测显著区域,提取图像中稳定区域,适用于光照变化下的交通标志检测。 - **HOG特征提取**:通过计算图像小区域的梯度直方图捕捉局部纹理信息,用于物体检测。 - **SVM**:寻找最大化间隔的超平面以分类样本。 整个算法流程图见下图。
|
5天前
|
人工智能 算法 数据安全/隐私保护
基于遗传优化的SVD水印嵌入提取算法matlab仿真
该算法基于遗传优化的SVD水印嵌入与提取技术,通过遗传算法优化水印嵌入参数,提高水印的鲁棒性和隐蔽性。在MATLAB2022a环境下测试,展示了优化前后的性能对比及不同干扰下的水印提取效果。核心程序实现了SVD分解、遗传算法流程及其参数优化,有效提升了水印技术的应用价值。
|
6天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于贝叶斯优化CNN-LSTM网络的数据分类识别算法matlab仿真
本项目展示了基于贝叶斯优化(BO)的CNN-LSTM网络在数据分类中的应用。通过MATLAB 2022a实现,优化前后效果对比明显。核心代码附带中文注释和操作视频,涵盖BO、CNN、LSTM理论,特别是BO优化CNN-LSTM网络的batchsize和学习率,显著提升模型性能。
|
11天前
|
存储
基于遗传算法的智能天线最佳阵列因子计算matlab仿真
本课题探讨基于遗传算法优化智能天线阵列因子,以提升无线通信系统性能,包括信号质量、干扰抑制及定位精度。通过MATLAB2022a实现的核心程序,展示了遗传算法在寻找最优阵列因子上的应用,显著改善了天线接收功率。
|
13天前
|
监控 算法 数据安全/隐私保护
基于三帧差算法的运动目标检测系统FPGA实现,包含testbench和MATLAB辅助验证程序
本项目展示了基于FPGA与MATLAB实现的三帧差算法运动目标检测。使用Vivado 2019.2和MATLAB 2022a开发环境,通过对比连续三帧图像的像素值变化,有效识别运动区域。项目包括完整无水印的运行效果预览、详细中文注释的代码及操作步骤视频,适合学习和研究。
|
21天前
|
算法
基于粒子群算法的分布式电源配电网重构优化matlab仿真
本研究利用粒子群算法(PSO)优化分布式电源配电网重构,通过Matlab仿真验证优化效果,对比重构前后的节点电压、网损、负荷均衡度、电压偏离及线路传输功率,并记录开关状态变化。PSO算法通过迭代更新粒子位置寻找最优解,旨在最小化网络损耗并提升供电可靠性。仿真结果显示优化后各项指标均有显著改善。
|
16天前
|
机器学习/深度学习 算法 数据挖掘
基于GWO灰狼优化的GroupCNN分组卷积网络时间序列预测算法matlab仿真
本项目展示了基于分组卷积神经网络(GroupCNN)和灰狼优化(GWO)的时间序列回归预测算法。算法运行效果良好,无水印展示。使用Matlab2022a开发,提供完整代码及详细中文注释。GroupCNN通过分组卷积减少计算成本,GWO则优化超参数,提高预测性能。项目包含操作步骤视频,方便用户快速上手。
|
17天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于WOA鲸鱼优化的GroupCNN分组卷积网络时间序列预测算法matlab仿真
本项目展示了一种基于WOA优化的GroupCNN分组卷积网络时间序列预测算法。使用Matlab2022a开发,提供无水印运行效果预览及核心代码(含中文注释)。算法通过WOA优化网络结构与超参数,结合分组卷积技术,有效提升预测精度与效率。分组卷积减少了计算成本,而WOA则模拟鲸鱼捕食行为进行优化,适用于多种连续优化问题。