算法复杂度分析Word格式文档下载.docx
- 文档编号:20451694
- 上传时间:2023-01-23
- 格式:DOCX
- 页数:17
- 大小:52.09KB
算法复杂度分析Word格式文档下载.docx
《算法复杂度分析Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《算法复杂度分析Word格式文档下载.docx(17页珍藏版)》请在冰豆网上搜索。
}
解答:
T(n)=n-1,T(n)=O(n),这个函数是按线性阶递增的。
(2)x=n;
//n>
1
while(x>
=(y+1)*(y+1))
y++;
T(n)=n1/2,T(n)=O(n1/2),最坏的情况是y=0,那么循环的次数是n1/2次,这是一个按平方根阶递增的函数。
(3)x=91;
y=100;
while(y>
0)
if(x>
100)
{x=x-10;
y--;
}
elsex++;
T(n)=O
(1),这个程序看起来有点吓人,总共循环运行了1000次,但是我们看到n没有?
没。
这段程序的运行是和n无关的,就算它再循环一万年,我们也不管他,只是一个常数阶的函数
2、算法复杂度编辑
算法复杂度,即算法在编写成可执行程序后,运行时所需要的资源,资源包括时间资源和内存资源。
中文名
算法复杂度
影
响
效率
分
类
时间复杂度和空间复杂度
关
键
输入量
相
关
时间复杂度
应
用
数学
1简介
2时间复杂度
3空间复杂度
4复杂度分析
1简介编辑
同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。
算法分析的目的在于选择合适算法和改进算法。
一个算法的评价主要从时间复杂度和空间复杂度来考虑。
2时间复杂度编辑
(1)时间频度
一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。
但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。
并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。
一个算法中的语句执行次数称为语句频度或时间频度。
记为T(n)。
算法的时间复杂度是指执行算法所需要的计算工作量。
(2)时间复杂度
在刚才提到的时间频度中,n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。
但有时我们想知道它变化时呈现什么规律。
为此,我们引入时间复杂度概念。
一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。
记作T(n)=O(f(n)),称O(f(n))为算法的渐进时间复杂度,简称时间复杂度。
在各种不同算法中,若算法中语句执行次数为一个常数,则时间复杂度为O
(1),另外,在时间频度不相同时,时间复杂度有可能相同,如T(n)=n^2+3n+4与T(n)=4n^2+2n+1它们的频度不同,但时间复杂度相同,都为O(n^2)。
按数量级递增排列,常见的时间复杂度有:
常数阶O
(1),对数阶O(log2n)(以2为底n的对数,下同),线性阶O(n),
线性对数阶O(nlog2n),平方阶O(n^2),立方阶O(n^3),...,
k次方阶O(n^k),指数阶O(2^n)。
随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越低。
算法的时间性能分析
(1)算法耗费的时间和语句频度
一个算法所耗费的时间=算法中每条语句的执行时间之和
每条语句的执行时间=语句的执行次数(即频度(FrequencyCount))×
语句执行一次所需时间
算法转换为程序后,每条语句执行一次所需的时间取决于机器的指令性能、速度以及编译所产生的代码质量等难以确定的因素。
若要独立于机器的软、硬件系统来分析算法的时间耗费,则设每条语句执行一次所需的时间均是单位时间,一个算法的时间耗费就是该算法中所有语句的频度之和。
求两个n阶方阵的乘积C=A×
B,其算法如下:
#definen100//n可根据需要定义,这里假定为100
voidMatrixMultiply(intA[a],intB[n][n],intC[n][n])
{//右边列为各语句的频度
inti,j,k;
(1)for(i=0;
i<
n;
i++)n+1
(2)for(j=0;
j<
j++){n(n+1)
(3)C[i][j]=0;
n2
(4)for(k=0;
k<
k++)n2(n+1)
(5)C[i][j]=C[i][j]+A[i][k]*B[k][j];
n3
该算法中所有语句的频度之和(即算法的时间耗费)为:
T(n)=2n3+3n2+2n+1(1.1)
分析:
语句
(1)的循环控制变量i要增加到n,测试到i=n成立才会终止。
故它的频度是n+1。
但是它的循环体却只能执行n次。
语句
(2)作为语句
(1)循环体内的语句应该执行n次,但语句
(2)本身要执行n+1次,所以语句
(2)的频度是n(n+1)。
同理可得语句(3),(4)和(5)的频度分别是n2,n2(n+1)和n3。
算法MatrixMultiply的时间耗费T(n)是矩阵阶数n的函数。
(2)问题规模和算法的时间复杂度
算法求解问题的输入量称为问题的规模(Size),一般用一个整数表示。
矩阵乘积问题的规模是矩阵的阶数。
一个图论问题的规模则是图中的顶点数或边数。
一个算法的时间复杂度(TimeComplexity,也称时间复杂性)T(n)是该算法的时间耗费,是该算法所求解问题规模n的函数。
当问题的规模n趋向无穷大时,时间复杂度T(n)的数量级(阶)称为算法的渐进时间复杂度。
算法MatrixMultiply的时间复杂度T(n)如(1.1)式所示,当n趋向无穷大时,显然有T(n)~O(n^3);
这表明,当n充分大时,T(n)和n^3之比是一个不等于零的常数。
即T(n)和n^3是同阶的,或者说T(n)和n^3的数量级相同。
记作T(n)=O(n^3)是算法MatrixMultiply的渐近时间复杂度。
(3)渐进时间复杂度评价算法时间性能
主要用算法时间复杂度的数量级(即算法的渐近时间复杂度)评价一个算法的时间性能。
算法MatrixMultiply的时间复杂度一般为T(n)=O(n^3),f(n)=n^3是该算法中语句(5)的频度。
下面再举例说明如何求算法的时间复杂度。
交换i和j的内容。
Temp=i;
i=j;
j=temp;
以上三条单个语句的频度均为1,该程序段的执行时间是一个与问题规模n无关的常数。
算法的时间复杂度为常数阶,记作T(n)=O
(1)。
注意:
如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。
此类算法的时间复杂度是O
(1)。
变量计数之一:
(1)x=0;
y=0;
(2)for(k-1;
k<
=n;
k++)
(3)x++;
(4)for(i=1;
i<
i++)
(5)for(j=1;
j++)
(6)y++;
一般情况下,对步进循环语句只需考虑循环体中语句的执行次数,忽略该语句中步长加1、终值判别、控制转移等成分。
因此,以上程序段中频度最大的语句是(6),其频度为f(n)=n^2,所以该程序段的时间复杂度为T(n)=O(n^2)。
当有若干个循环语句时,算法的时间复杂度是由嵌套层数最多的循环语句中最内层语句的频度f(n)决定的。
变量计数之二:
(1)x=1;
(2)for(i=1;
(3)for(j=1;
=i;
(4)for(k=1;
=j;
(5)x++;
该程序段中频度最大的语句是(5),内循环的执行次数虽然与问题规模n没有直接关系,但是却与外层循环的变量取值有关,而最外层循环的次数直接与n有关,因此可以从内层循环向外层分析语句(5)的执行次数:
则该程序段的时间复杂度为T(n)=O(n^3/6+低次项)=O(n^3)。
(4)算法的时间复杂度不仅仅依赖于问题的规模,还与输入实例的初始状态有关。
在数值A[0..n-1]中查找给定值K的算法大致如下:
(1)i=n-1;
(2)while(i>
=0&
&
(A[i]!
=k))
(3)i--;
(4)returni;
此算法中的语句(3)的频度不仅与问题规模n有关,还与输入实例中A的各元素取值及K的取值有关:
①若A中没有与K相等的元素,则语句(3)的频度f(n)=n;
②若A的最后一个元素等于K,则语句(3)的频度f(n)是常数0。
3空间复杂度编辑
与时间复杂度类似,空间复杂度是指算法在计算机内执行时所需存储空间的度量。
记作:
S(n)=O(f(n))
算法执行期间所需要的存储空间包括3个部分:
·
算法程序所占的空间;
输入的初始数据所占的存储空间;
算法执行过程中所需要的额外空间。
在许多实际问题中,为了减少算法所占的存储空间,通常采用压缩存储技术。
复杂度分析编辑
通常一个算法的复杂度是由其输入量决定的,随着输入的增加,
复杂度
不同算法的复杂度增长速度如右图所示:
为了降低算法复杂度,应当同时考虑到输入量,设计较好的算法。
3、算法复杂度分析
一、时间复杂度
算法复杂度分为时间复杂度和空间复杂度。
其作用:
时间复杂度是度量算法执行的时间长短;
而空间复杂度是度量算法所需存储空间的大小。
任何算法运行所需要的时间几乎总是取决于他所处理的数据量,在这里我们主要说时间复杂度。
对于一个给定计算机的算法程序,我们能画出运行时间的函数图。
1.一般情况下,算法的基本操作重复执行的次数是模块n的某一个函数f(n),因此,算法的时间复杂度记做:
T(n)=O(f(n))
分析:
随着模块n的增大,算法执行的时间的增长率和f(n)的增长率成正比,所以f(n)越小,算法的时间复杂度越低,算法的效率越高。
2.在计算时间复杂度的时候,先找出算法的基本操作,然后根据相应的各语句确定它的执行次数,再找出T(n)的同数量级(它的同数量级有以下:
1<
Log2n<
n<
nLog2n<
n的平方<
n的三次方<
2的n次方<
n!
),找出后,f(n)=该数量级,若T(n)/f(n)求极限可得到一常数c,则时间复杂度T(n)=O(f(n)),例:
[java]
viewplaincopy
1.for(i=1;
++i)
2.{
3.for(j=1;
++j)
4.{
5.c[
i
][
j
]=0;
//该步骤属于基本操作
执行次数:
n的平方
次
6.for(k=1;
++k)
7.c[
]+=a[
k
]*b[
];
n的三次方
8.}
9.}
则有T(n)=n的平方+n的三次方,根据上面括号里的同数量级,我们可以确定n的三次方为T(n)的同数量级,则有f(n)=n的三次方,然后根据T(n)/f(n)求极限可得到常数c。
则该算法的时间复杂度:
T(n)=O(n^3)注:
n^3即是n的3次方。
3.在pascal中比较容易理解,容易计算的方法是:
看看有几重for循环,只有一重则时间复杂度为O(n),二重则为O(n^2),依此类推,如果有二分则为O(logn),二分例如快速幂、二分查找,如果一个for循环套一个二分,那么时间复杂度则为O(nlogn)。
按数量级递增排列,常见的时间复杂度有:
常数阶O
(1),对数阶O(log2n),线性阶O(n),
线性对数阶O(nlog2n),平方阶O(n^2),立方阶O(n^3),...,
k次方阶O(n^k),指数阶O(2^n)。
根据定义,可以归纳出基本的计算步骤
1.计算出基本操作的执行次数T(n)
基本操作即算法中的每条语句(以;
号作为分割),语句的执行次数也叫做语句的频度。
在做算法分析时,一般默认为考虑最坏的情况。
2.计算出T(n)的数量级
求T(n)的数量级,只要将T(n)进行如下一些操作:
忽略常量、低次幂和最高次幂的系数,令f(n)=T(n)的数量级。
3.用大O来表示时间复杂度
当n趋近于无穷大时,如果lim(T(n)/f(n))的值为不等于0的常数,则称f(n)是T(n)的同数量级函数。
记作T(n)=O(f(n))。
一个示例:
1.
int
num1,
num2;
2.
for(int
i=0;
i++){
3.
num1
+=
1;
4.
j=1;
j*=2){
5.
num2
num1;
6.
7.}
1.
语句intnum1,num2;
的频度为1;
语句i=0;
语句i<
i++;
num1+=1;
j=1;
的频度为n;
语句j<
j*=2;
num2+=num1;
的频度为n*log2n;
T(n)=2+4n+3n*log2n
2.
忽略掉T(n)中的常量、低次幂和最高次幂的系数,f(n)=n*log2n
3.
lim(T(n)/f(n))=(2+4n+3n*log2n)/(n*log2n)
=2*(1/n)*(1/log2n)+4*(1/log2n)+3
当n趋向于无穷大,1/n趋向于0,1/log2n趋向于0
所以极限等于3。
T(n)=O(n*log2n)
简化的计算步骤
再来分析一下,可以看出,决定算法复杂度的是执行次数最多的语句,这里是num2+=num1,一般也是最内循环的语句。
并且,通常将求解极限是否为常量也省略掉?
于是,以上步骤可以简化为:
1.找到执行次数最多的语句
2.计算语句执行次数的数量级
3.用大O来表示结果
继续以上述算法为例,进行分析:
执行次数最多的语句为num2+=num1
T(n)=n*log2n
f(n)=n*log2n
//lim(T(n)/f(n))=1
T(n)=O(n*log2n)
二、插入排序算法的时间复杂度
现在研究一下插入排序算法的执行时间,按照习惯,输入长度LEN以下用n表示。
设循环中各条语句的执行时间分别是c1、c2、c3、c4、c5这样五个常数:
1.void
insertion_sort(void)
执行时间
i,
j,
key;
for
(j
=
<
LEN;
j++)
{
key
a[j];
c1
-
c2
7.
while
(i
>
0
a[i]
key)
8.
a[i+1]
a[i];
c3
9.
i--;
c4
10.
11.
c5
12.
13.}
显然外层for循环的执行次数是n-1次,假设内层的while循环执行m次,则总的执行时间粗略估计是(n-1)*(c1+c2+c5+m*(c3+c4))。
当然,for和while后面()括号中的赋值和条件判断的执行也需要时间,而我没有设一个常数来表示,这不影响我们的粗略估计。
这里有一个问题,m不是个常数,也不取决于输入长度n,而是取决于具体的输入数据。
在最好情况下,数组a的原始数据已经排好序了,while循环一次也不执行,总的执行时间是(c1+c2+c5)*n-(c1+c2+c5),可以表示成an+b的形式,是n的线性函数(LinearFunction)。
那么在最坏情况(WorstCase)下又如何呢?
所谓最坏情况是指数组a的原始数据正好是从大到小排好序的,请读者想一想为什么这是最坏情况,然后把上式中的m替换掉算一下执行时间是多少。
数组a的原始数据属于最好和最坏情况的都比较少见,如果原始数据是随机的,可称为平均情况(AverageCase)。
如果原始数据是随机的,那么每次循环将已排序的子序列a[1..j-1]与新插入的元素key相比较,子序列中平均都有一半的元素比key大而另一半比key小,请读者把上式中的m替换掉算一下执行时间是多少。
最后的结论应该是:
在最坏情况和平均情况下,总的执行时间都可以表示成an2+bn+c的形式,是n的二次函数(QuadraticFunction)。
在分析算法的时间复杂度时,我们更关心最坏情况而不是最好情况,理由如下:
1.最坏情况给出了算法执行时间的上界,我们可以确信,无论给什么输入,算法的执行时间都不会超过这个上界,这样为比较和分析提供了便利。
2.对于某些算法,最坏情况是最常发生的情况,例如在数据库中查找某个信息的算法,最坏情况就是数据库中根本不存在该信息,都找遍了也没有,而某些应用场合经常要查找一个信息在数据库中存在不存在。
3.虽然最坏情况是一种悲观估计,但是对于很多问题,平均情况和最坏情况的时间复杂度差不多,比如插入排序这个例子,平均情况和最坏情况的时间复杂度都是输入长度n的二次函数。
比较两个多项式a1n+b1和a2n2+b2n+c2的值(n取正整数)可以得出结论:
n的最高次指数是最主要的决定因素,常数项、低次幂项和系数都是次要的。
比如100n+1和n2+1,虽然后者的系数小,当n较小时前者的值较大,但是当n>
100时,后者的值就远远大于前者了。
如果同一个问题可以用两种算法解决,其中一种算法的时间复杂度为线性函数,另一种算法的时间复杂度为二次函数,当问题的输入长度n足够大时,前者明显优于后者。
因此我们可以用一种更粗略的方式表示算法的时间复杂度,把系数和低次幂项都省去,线性函数记作Θ(n),二次函数记作Θ(n2)。
Θ(g(n))表示和g(n)同一量级的一类函数,例如所有的二次函数f(n)都和g(n)=n2属于同一量级,都可以用Θ(n2)来表示,甚至有些不是二次函数的也和n2属于同一量级,例如2n2+3lgn。
“同一量级”这个概念可以用下图来说明(该图出自[算法导论]):
图
11.2.
Θ-notation
如果可以找到两个正的常数c1和c2,使得n足够大的时候(也就是n≥n0的时候)f(n)总是夹在c1g(n)和c2g(n)之间,就说f(n)和g(n)是同一量级的,f(n)就可以用Θ(g(n))来表示。
以二次函数为例,比如1/2n2-3n,要证明它是属于Θ(n2)这个集合的,我们必须确定c1、c2和n0,这些常数不随n改变,并且当n≥n0以后,c1n2≤1/2n2-3n≤c2n2总是成立的。
为此我们从不等式的每一边都除以n2,得到c1≤1/2-3/n≤c2。
见下图:
11.3.
1/2-3/n
这样就很容易看出来,无论n取多少,该函数一定小于1/2,因此c2=1/2,当n=6时函数值为0,n>
6时该函数都大于0,可以取n0=7,c1=1/14,这样当n≥n0时都有1/2-3/n≥c1。
通过这个证明过程可以得出结论,当n足够大时任何an2+bn+c都夹在c1n2和c2n2之间,相对于n2项来说bn+c的影响可以忽略,a可以通过选取合适的c1、c2来补偿。
几种常见的时间复杂度函数按数量级从小到大的顺序依次是:
Θ(lgn),Θ(sqrt(n)),Θ(n),Θ(nlgn),Θ(n2),Θ(n3),Θ(2n),Θ(n!
)。
其中,lgn通常表示以10为底n的对数,但是对于Θ-notation来说,Θ(lgn)和Θ(log2n)并无区别(想一想这是为什么),在算法分析中lgn通常表示以2为底n的对数。
可是什么算法的时间复杂度里会出现lgn呢?
回顾插入排序的时间复杂度分析,无非是循环体的执行时间乘以循环次数,只有加和乘运算,怎么会出来lg呢?
下一节归并排序的时间复杂度里面就有lg,请读者留心lg运算是从哪出来的。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 复杂度 分析