计算机时间复杂度和空间复杂度

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

计算机时间复杂度和空间复杂度
⾸先了解⼀下⼏个概念。

⼀个是时间复杂度,⼀个是渐近时间复杂度。

前者是某个算法的时间耗费,它是该算法所求解问题规模n的函数,⽽后者是指当问题规模趋向⽆穷⼤时,该算法时间复杂度的数量级。

当我们评价⼀个算法的时间性能时,主要标准就是算法的渐近时间复杂度,因此,在算法分析时,往往对两者不予区分,经常是将渐近时间复杂度T(n)=O(f(n))简称为时间复杂度,其中的f(n)⼀般是算法中频度最⼤的语句频度。

此外,算法中语句的频度不仅与问题规模有关,还与输⼊实例中各元素的取值相关。

但是我们总是考虑在最坏的情况下的时间复杂度。

以保证算法的运⾏时间不会⽐它更长。

常见的时间复杂度,按数量级递增排列依次为:常数阶O(1)、对数阶O(log2n)、线性阶O(n)、线性对数阶O(nlog2n)、平⽅阶O(n^2)、⽴⽅阶O(n^3)、k次⽅阶O(n^k)、指数阶O(2^n)。

1. ⼤O表⽰法
定义
设⼀个程序的时间复杂度⽤⼀个函数 T(n) 来表⽰,对于⼀个查找算法,如下:
int seqsearch( int a[], const int n, const int x)
{
int i = 0;
for (; a[i] != x && i < n ; i++ );
if ( i == n) return -1;
else return i;
}
这个程序是将输⼊的数值顺序地与数组中地元素逐个⽐较,找出与之相等地元素。

在第⼀个元素就找到需要⽐较⼀次,在第⼆个元素找到需要⽐较2次,…… ,在第n个元素找到需要⽐较n次。

对于有n个元素的数组,如果每个元素被找到的概率相等,那么查找成功的平均⽐较次数为:
f(n) = 1/n (n + (n-1) + (n-2) + ... + 1) = (n+1)/2 = O(n)
这就是传说中的⼤O函数的原始定义。

⽤⼤O来表述
要全⾯分析⼀个算法,需要考虑算法在最坏和最好的情况下的时间代价,和在平均情况下的时间代价。

对于最坏情况,采⽤⼤O表⽰法的⼀般提法(注意,这⾥⽤的是“⼀般提法”)是:当且仅当存在正整数c和n0,使得 T(n) <= c*f(n)对于所有的n >= n0 都成⽴。

则称该算法的渐进时间复杂度为T(n) = O(f(n))。

这个应该是⾼等数学⾥⾯的第⼀章极限⾥⾯的知识。

这⾥f(n) = (n+1)/2, 那么c * f(n)也就是⼀个⼀次函数。

就是在图象上看就是如果这个函数在c*f(n)的下⾯,就是复杂度为T(n) = O(f(n))。

对于对数级,我们⽤⼤O记法记为O(log2N)就可以了。

规则
1)加法规则
T(n,m) = T1(n) + T2(n) = O ( max (f(n), g(m) )
2) 乘法规则
T(n,m) = T1(n) * T2(m) = O (f(n) * g(m))
3)⼀个特例
在⼤O表⽰法⾥⾯有⼀个特例,如果T1(n) = O©, c是⼀个与n⽆关的任意常数,T2(n) = O ( f(n) ) 则有
T(n) = T1(n) * T2(n) = O ( c*f(n) ) = O( f(n) ).
也就是说,在⼤O表⽰法中,任何⾮0正常数都属于同⼀数量级,记为O(1)。

4)⼀个经验规则
有如下复杂度关系
c < log2N < n < n * Log2N < n^2 < n^3 < 2^n < 3^n < n!
其中c是⼀个常量,如果⼀个算法的复杂度为c 、 log2N 、n 、 n*log2N ,那么这个算法时间效率⽐较⾼,如果是 2^n , 3^n ,n!,那么稍微⼤⼀些的n就会令这个算法不能动了,居于中间的⼏个则差强⼈意.
1)基本知识点:没有循环的⼀段程序的复杂度是常数,⼀层循环的复杂度是O(n),两层循环的复杂度是O(n^2)? (我⽤^2表⽰平⽅,同理 ^3表⽰⽴⽅);
2)⼆维矩阵的标准差,残差,信息熵,fft2,dwt2,dct2的时间复杂度: 标准差和残差可能O(n),FFT2是O(nlog(n)),DWT2可能也是
O(nlog(n));信息熵要求概率,⽽dct的过程和jpeg⼀样。

因为和jpeg⼀样,对⼆难矩阵处理了.Y=T*X*T',Z=Y.*Mask,这样⼦,还有分成8*8⼦图像了;
3)example:
1、设三个函数f,g,h分别为 f(n)=100n^3+n^2+1000 , g(n)=25n^3+5000n^2 , h(n)=n^1.5+5000nlgn
请判断下列关系是否成⽴:
(1) f(n)=O(g(n))
(2) g(n)=O(f(n))
(3) h(n)=O(n^1.5)
(4) h(n)=O(nlgn)
这⾥我们复习⼀下渐近时间复杂度的表⽰法T(n)=O(f(n)),这⾥的"O"是数学符号,它的严格定义是"若T(n)和f(n)是定义在正整数集合上的两个函数,则T(n)=O(f(n))表⽰存在正的常数C和n0 ,使得当n≥n0时都满⾜0≤T(n)≤C?f(n)。

"⽤容易理解的话说就是这两个函数当整型⾃变量n趋向于⽆穷⼤时,两者的⽐值是⼀个不等于0的常数。

这么⼀来,就好计算了吧。

◆ (1)成⽴。

题中由于两个函数的最⾼次项都是n^3,因此当n→∞时,两个函数的⽐值是⼀个常数,所以这个关系式是成⽴的。

◆(2)成⽴。

与上同理。

◆(3)成⽴。

与上同理。

◆(4)不成⽴。

由于当n→∞时n^1.5⽐nlgn递增的快,所以h(n)与nlgn的⽐值不是常数,故不成⽴。

2、设n为正整数,利⽤⼤"O"记号,将下列程序段的执⾏时间表⽰为n的函数。

(1) i=1; k=0
while(i<n)
{ k=k+10*i;i++;
}
解答: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--;}
else x++;
解答: T(n)=O(1),这个程序看起来有点吓⼈,总共循环运⾏了1000次,但是我们看到n没有? 没。

这段程序的运⾏是和n⽆关的,就算它再循环⼀万年,我们也不管他,只是⼀个常数阶的函数。

同⼀问题可⽤不同算法解决,⽽⼀个算法的质量优劣将影响到算法乃⾄程序的效率。

算法分析的⽬的在于选择合适算法和改进算法。

⼀个算法的评价主要从时间复杂度和空间复杂度来考虑。

1、时间复杂度
(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)=n2+3n+4与T(n)=4n2+2n+1它们的频度不同,但时间复杂度相同,都为O(n2)。

按数量级递增排列,常见的时间复杂度有:
常数阶O(1),对数阶O(log2n),线性阶O(n),
线性对数阶O(nlog2n),平⽅阶O(n2),⽴⽅阶O(n3),...,
k次⽅阶O(nk),指数阶O(2n)。

随着问题规模n的不断增⼤,上述时间复杂度不断增⼤,算法的执⾏效率越低。

2、空间复杂度
与时间复杂度类似,空间复杂度是指算法在计算机内执⾏时所需存储空间的度量。

记作:
S(n)=O(f(n))
我们⼀般所讨论的是除正常占⽤内存开销外的辅助存储单元规模。

讨论⽅法与时间复杂度类似,不再赘述。

(3)渐进时间复杂度评价算法时间性能
主要⽤算法时间复杂度的数量级(即算法的渐近时间复杂度)评价⼀个算法的时间性能。

【例3.7】有两个算法A1和A2求解同⼀问题,时间复杂度分别是T1(n)=100n2,T2(n)=5n3。

(1)当输⼊量n<20时,有T1(n)>T2(n),后者花费的时间较少。

(2)随着问题规模n的增⼤,两个算法的时间开销之⽐5n3/100n2=n/20亦随着增⼤。

即当问题规模较⼤时,算法A1⽐算法A2要有效地多。

它们的渐近时间复杂度O(n2)和O(n3)从宏观上评价了这两个算法在时间⽅⾯的质量。

在算法分析时,往往对算法的时间复杂度和渐近时间复杂度不予区分,⽽经常是将渐近时间复杂度T(n)=O(f(n))简称为时间复杂度,其中的f(n)⼀般是算法中频度最⼤的语句频度。

【例3.8】算法MatrixMultiply的时间复杂度⼀般为T(n)=O(n3),f(n)=n3是该算法中语句(5)的频度。

下⾯再举例说明如何求算法的时间复杂度。

【例3.9】交换i和j的内容。

Temp=i;
i=j;
j=temp;
以上三条单个语句的频度均为1,该程序段的执⾏时间是⼀个与问题规模n⽆关的常数。

算法的时间复杂度为常数阶,记作T(n)=O(1)。

如果算法的执⾏时间不随着问题规模n的增加⽽增长,即使算法中有上千条语句,其执⾏时间也不过是⼀个较⼤的常数。

此类算法的时间复杂度是O(1)。

【例3.10】变量计数之⼀。

(1) x=0;y=0;
(2) for(k-1;k<=n;k++)
(3) x++;
(4) for(i=1;i<=n;i++)
(5) for(j=1;j<=n;j++)
(6) y++;
⼀般情况下,对步进循环语句只需考虑循环体中语句的执⾏次数,忽略该语句中步长加1、终值判别、控制转移等成分。

因此,以上程序段中频度最⼤的语句是(6),其频度为f(n)=n2,所以该程序段的时间复杂度为T(n)=O(n2)。

当有若⼲个循环语句时,算法的时间复杂度是由嵌套层数最多的循环语句中最内层语句的频度f(n)决定的。

【例3.11】变量计数之⼆。

(1) x=1;
(2) for(i=1;i<=n;i++)
(3) for(j=1;j<=i;j++)
(4) for(k=1;k<=j;k++)
(5) x++;
该程序段中频度最⼤的语句是(5),内循环的执⾏次数虽然与问题规模n没有直接关系,但是却与外层循环的变量取值有关,⽽最外层循环的次数直接与n有关,因此可以从内层循环向外层分析语句(5)的执⾏次数:
则该程序段的时间复杂度为T(n)=O(n3/6+低次项)=O(n3)。

(4)算法的时间复杂度不仅仅依赖于问题的规模,还与输⼊实例的初始状态有关。

【例3.12】在数值A[0..n-1]中查找给定值K的算法⼤致如下:
(1)i=n-1;
(2)while(i>=0&&(A[i]!=k))
(3) i--;
(4)return i;
此算法中的语句(3)的频度不仅与问题规模n有关,还与输⼊实例中A的各元素取值及K的取值有关:
①若A中没有与K相等的元素,则语句(3)的频度f(n)=n;
②若A的最后⼀个元素等于K,则语句(3)的频度f(n)是常数0。

(5)最坏时间复杂度和平均时间复杂度
最坏情况下的时间复杂度称最坏时间复杂度。

⼀般不特别说明,讨论的时间复杂度均是最坏情况下的时间复杂度。

这样做的原因是:最坏情况下的时间复杂度是算法在任何输⼊实例上运⾏时间的上界,这就保证了算法的运⾏时间不会⽐任何更长。

【例3.19】查找算法【例1·8】在最坏情况下的时间复杂度为T(n)=0(n),它表⽰对于任何输⼊实例,该算法的运⾏时间不可能⼤于0(n)。

平均时间复杂度是指所有可能的输⼊实例均以等概率出现的情况下,算法的期望运⾏时间。

常见的时间复杂度按数量级递增排列依次为:常数0(1)、对数阶0(log2n)、线形阶0(n)、线形对数阶0(nlog2n)、平⽅阶0(n2)⽴⽅阶
0(n3)、…、k次⽅阶0(nk)、指数阶0(2n)。

显然,时间复杂度为指数阶0(2n)的算法效率极低,当n值稍⼤时就⽆法应⽤。

类似于时间复杂度的讨论,⼀个算法的空间复杂度(Space Complexity)S(n)定义为该算法所耗费的存储空间,它也是问题规模n的函数。

渐近空间复杂度也常常简称为空间复杂度。

算法的时间复杂度和空间复杂度合称为算法的复杂度。

相关文档
最新文档