您的位置:首页 > 其它

算法——从时间复杂度开始说起

2017-02-12 21:35 162 查看

算法——从时间复杂度开始说起

相应的练习代码:https://github.com/liuxuan320/Algorithm_Exercises

0.写在前面

不知道怎么回事,所有的LATEX的公式发表后都缩成一团了,实际上我看的时候是没什么问题的,如果有需要可以联系我。

1.算法的定义

算法作为计算机程序设计中的重中之重,在著名的公式中:

程序=数据结构+算法

算法被视作是程序的灵魂,因此有必要学好算法。

但是算法其实并不是那么特殊,如果用做人类思维的角度来看,就是解决问题的方法,只不过这个方法既特殊又一般。

首先给出算法的定义,这并不是对的。但是这也是迫不得已而为之的。

算法就是一组有穷的规则,它规定了解决某一特定类型问题的一系列运算。

简单来说,就是用来解决某一特定类型的普适的解决方法。这也是我说它为什么既特殊又一般的原因。

2.算法的特性

但是作为算法的定义,这样说明并不能告诉你什么样是一个算法,我们通常去判别一个事物时,使用的都是具有约束条件的描述,即该事物所具备的属性/性质/特性。因此我们这里给出算法的5个必要性特性,也就是说少了其中任何一条都不能称之为算法:

1.确定性

所谓的确定性,并不是指整个算法的确定性,而是说算法的每一种运算、操作等必须具有确切的定义,并不能使用这种5/0等无意义的操作,更不用讲那些从来没听说过或者是天方夜谭的运算操作。

2.能行性/可行性

能行性主要指的是算法中优待实现的运算都是基本运算。每种运算至少在原理上能由人用纸和笔在有限的时间内完成。

3.输入

算法的输入可以有0个或者多个。

4.输出

算法必须有一个及以上的输出。

5.有穷性

这个更不用说了,一个算法应该总是在执行了有穷步的运算之后终止。

值得指出的是算法必须满足上述全部5条特性,只满足前4条的不能成为算法,只能称为计算过程。操作系统就是一个典型的计算过程。

3.算法的组成部分

在讲算法的时候,我们其实把更多的精力投放在了算法的其中的一个部分,但实际上,算法包含以下5个部分:

1.如何设计算法

很显然,如何设计算法在初学者身上很难进行狭义上的“设计”,但是对于广义上的设计我们还是可以进行很多尝试。

2.如何表示算法

如何表示算法就是在想出一个算法后,如何让它具现化,也就是从“意识”变为“物质”,从而根据这个“物质”算法,编写特定的程序。

我们常用的有流程图、伪代码、SPARK语言等作为我们描述算法的工具,这个因人而异。

3.如何确认算法

从这部分开始,我们平时学习算法的过程中就忽略了许多。所谓的确认算法,就是要证明它对所有的可能的合法输入都能给出正确的答案。通常来讲,这一部分我们都省略了,其中很重要的原因是因为这一部分被称为“程序证明”,至今还未有重大突破,但是好在,我们一般情况下没有进行狭义上的“设计”,而且很多算法的证明前人都已经给出了“无错误”的“证明”(使用程序测试替代理论推导),因此我们还是对此有一定的认识和了解的。

4.如何分析算法

既然第3步我们没有办法用自身的水平来进行“躬行”,那么第4部分就显得尤为重要了。对于算法的分析也是一个很重要的部分,通常我们主要对算法的时间复杂度空间复杂度进行一定的分析。接下来我们就会以一个例子来开始我们的算法之路。

5.如何测试程序

测试程序很大一部分原因是因为第3步难以实现的妥协之物,主要用来“证明”算法的“无错误”性,但是“无错误”并不代表“正确”,因为有可能在我们未知的运行状态下会出现BUG,然而这也是无奈之举。很多算法的进步都是从测试中不断的优化,从而获得更好的时空复杂度。

4.算法的时间复杂度

算法的时间复杂度通常并不能准确的预估出,因此我们经常使用的是一种粗略的估计,即预测算法的时间复杂度的上界和下界的数量级。那么,就会有如下三个定义:

定义2.1 如果存在两个正常数c和n0,对于所有的n≥n0,有

|f(n)|≤c|g(n)|

则记作f(n)=O(g(n)),我们把O(g(n))称为其算法的上界。

定义2.2 如果存在两个正常数c和n0,对于所有的n>n0,有

|f(n)|≥c|g(n)|

则记作f(n)=Ω(g(n)),我们把Ω(g(n))称为其算法的下界。

定义2.3 如果存在正常数c1、c2和n0,对于所有的n>n0,有

c1|g(n)|≤|f(n)|≤c2|g(n)|

则记为f(n)=Θ(g(n)),也就是说该算法在最好和最坏情况下的计算时时间就一个常因子范围内而言是相同的。

5.算法的一个例子

接下来,我们就以一个例子来结束我们的算法导论讲解。

证明:

若A(n)=amnm+...+a1n+a0是一个m次多项式,则A(n)=Θ(nm)

解:

(1)首先证明其上界

取n_0=1,当n≥n0时,有

|A(n)|≤|am|nm+...+|a1|n+|a0|

≤(|am|+|am−1|/n+...+|a0|/nm)nm

≤(|am|+...+|a0|)nm

选取c0=|am|+...+|a0|,得|A(n)|≤c0|nm|

(2)其次证明其下界

|A(n)|=|amnm+...+a1n+a0|≥|am|nm−|am−1|nm−1...−|a0|

设F(n)=|am|nm−|am−1|nm−1...−|a0|

由F(n)的单调性易知,存在nt>0使得F(n)在n>nt时单调递增且速率逐渐加快

取n>1,且nt0>nt,F(nt0)>0

则当n>nt0时,F(n)>0

即|am|nm−|am−1|nm−1...−|a0|

=[|am|−(|am−1|/n+...+|a0|/nm)]nm

>[|am|−(|am−1|/nt0+...+|a0|/nmt0)]nm

>[|am|−(|am−1|/nt0+...+|a0|/nmt0)]nmt0>0

所以|am|−(|am−1|/nt0+...+|a0|/nmt0)>0

取n0=nt0,c1=|am|−(|am−1|/nt0+...+|a0|/nmt0)>0

即存在正常数c1和n0,对所有n>n0有

|A(n)|≥c1|nm|

综上所述,存在正常数c0、c1和n0,对于所有的n>n0

有c1|nm|≤|A(n)|≤c0|nm|

6.算法小结

以上就是我们算法的开始,主要讲了算法的定义、特性、组成部分,以及其时间复杂度,并使用了一个例子来证明了其时间复杂度。本章内容多半时理论,希望可以在以后的日子里多加揣摩。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  时间复杂度 算法