浅谈 计算时间复杂度和空间复杂度 ʕ •ᴥ•ʔ

算法复杂度分为时间复杂度和空间复杂度。

       求解算法的时间复杂度,其具体步骤是:

  ⑴ 找出算法中的基本语句;

  算法中执行次数最多的那条语句就是基本语句,通常是最内层循环的循环体。

  ⑵ 计算基本语句的执行次数的数量级;

  只需计算基本语句执行次数的数量级,这就意味着只要保证基本语句执行次数的函数中的最高次幂正确即可,可以忽略所有低次幂和最高次幂的系数。这样能够简化算法分析,并且使注意力集中在最重要的一点上:增长率。

  ⑶ 用大O记号表示算法的时间性能。

  将基本语句执行次数的数量级放入大O记号中。

  如果算法中包含嵌套的循环,则基本语句通常是最内层的循环体,如果算法中包含并列的循环,则将并列循环的时间复杂度相加。例如:

  for (i=1; i<=n; i++)
  x++;

  for (i=1; i<=n; i++)
  for (j=1; j<=n; j++)
  x++;

  第一个for循环的时间复杂度为O(n),第二个for循环的时间复杂度为O(n2),则整个算法的时间复杂度为O(n+n2)=O(n2)。

  常见的算法时间复杂度由小到大依次为:

  O(1)<O(log2n)<O(n)<O(nlog2n)<O(n2)<O(n3)< { O(2^n) < O(n!) < O(n^n) }

Ο(1)表示基本语句的执行次数是一个常数,一般来说,只要算法中不存在循环语句,其时间复杂度就是O(1)。O(log2n)、O(n)、O(nlog2n)、O(n2)和O(n3)称为多项式时间,而O(2n)和O(n!)称为指数时间。

最后三项用大括号把他们括起来是想要告诉大家,如果日后大家设计的算法推导出的“大O阶”是大括号中的这几位,那么趁早放弃这个算法,在去研究新的算法出来吧。因为大括号中的这几位即便是在 n 的规模比较小的情况下仍然要耗费大量的时间,算法的时间复杂度大的离谱,基本上就是“不可用状态”。

  在计算算法时间复杂度时有以下几个简单的程序分析法则: 
   (1).对于一些简单的输入输出语句或赋值语句,近似认为需要O(1)时间 
   (2).对于顺序结构,需要依次执行一系列语句所用的时间可采用大O下"求和法则" 求和法则:是指若算法的2个部分时间复杂度分别为 T1(n)=O(f(n))和 T2(n)=O(g(n)),则 T1(n)+T2(n)=O(max(f(n),g(n)))。特别地,若T1(m)=O(f(m)), T2(n)=O(g(n)),则 T1(m)+T2(n)=O(f(m)+g(n)) 
   (3).对于选择结构,如if语句,它的主要时间耗费是在执行then字句或else字句所用的时间,需注意的是检验条件也需要O(1)时间 
   (4).对于循环结构,循环语句的运行时间主要体现在多次迭代中执行循环体以及检验循环条件的时间耗费,一般可用大O下"乘法法则" 
乘法法则: 是指若算法的2个部分时间复杂度分别为 T1(n)=O(f(n))和 T2(n)=O(g(n)),则 T1*T2=O(f(n)*g(n)) 
   (5).对于复杂的算法,可以将它分成几个容易估算的部分,然后利用求和法则和乘法法则计算整个算法的时间复杂度

   另外还有以下2个运算法则:(1) 若g(n)=O(f(n)),则O(f(n))+O(g(n))=O(f(n));(2)O(Cf(n)) = O(f(n)),其中C是一个正常数。

给大家举些栗子叭。

 (1)、O(1) 

 Temp=i; i=j; j=temp;                    
 以上三条单个语句的频度均为1,该程序段的执行时间是一个与问题规模n无关的常数。算法的时间复杂度为常数阶,记作T(n)=O(1)。注意:如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。 

(2)、O(n2)

交换i和j的内容

1.sum=0;(一次)   

2.for(i=1;i<=n;i++) (n+1次)   

3.for(j=1;j<=n;j++)(n(n+1)次)   

4.sum++;(n(n+1)+1次) 

因为(2n2+n+1)=n2(即:去低阶项,去掉常数项,去掉高阶项的常参得到),所以T(n)= =O(n2);

一般情况下,对步进循环语句只需考虑循环体中语句的执行次数,忽略该语句中步长加1、终值判别、控制转移等成分,当有若干个循环语句时,算法的时间复杂度是由嵌套层数最多的循环语句中最内层语句的频度f(n)决定的。

(3)、O(n)  

1.a=0;   

2.b=1;               ①   

3.for (i=1;i<=n;i++) ②   

4.{s=a+b;            ③   

6.b=a;               ④     

7.a=s; }             ⑤ 

语句1的频度为2,语句2的频度为n,语句3的频度为n-1,语句4的频度为n-1,语句5的频度为n-1, 即T(n)=2+n+3(n-1)=4n-1=O(n). 

(4)、O(log2n) 

1. i=1;   ①   

2. while (i<=n)   

3. i=i*2; ② 

语句1的频度是1,设语句2的频度是f(n),则:2^f(n)<=n;f(n)<=log2n,取最大值f(n)=log2n,即T(n)=O(log2n) 

(5)、O(n3)  

1. for(i=0;i<n;i++){     

2. for(j=0;j<i;j++){   

3.for(k=0;k<j;k++)   

4.x=x+2; }}

当i=m,j=k的时候,内层循环的次数为k当i=m时, j可以取 0,1,...,m-1 ,所以这里最内循环共进行了0+1+...+m-1=(m-1)m/2次所以,i从0取到n,则循环共进行了:0+(1-1)*1/2+...+(n-1)n/2=n(n+1)(n-1)/6所以时间复杂度为O(n3).

然后我们来看看空间复杂度

一个程序的空间复杂度是指运行完一个程序所需内存的大小。利用程序的空间复杂度,可以对程序的运行所需要的内存多少有个预先估计。一个程序执行时除了需要存储空间和存储本身所使用的指令、常数、变量和输入数据外,还需要一些对数据进行操作的工作单元和存储一些为现实计算所需信息的辅助空间。程序执行时所需存储空间包括以下两部分。  

(1)固定部分。这部分空间的大小与输入/输出的数据的个数多少、数值无关。主要包括指令空间(即代码空间)、数据空间(常量、简单变量)等所占的空间。这部分属于静态空间。

(2)可变空间,这部分空间的主要包括动态分配的空间,以及递归栈所需的空间等。这部分的空间大小与算法有关。

一个算法所需的存储空间用f(n)表示。S(n)=O(f(n))  其中n为问题的规模,S(n)表示空间复杂度。

       对于一个算法,其时间复杂度和空间复杂度往往是相互影响的。当追求一个较好的时间复杂度时,可能会使空间复杂度的性能变差,即可能导致占用较多的存储空间;反之,求一个较好的空间复杂度时,可能会使时间复杂度的性能变差,即可能导致占用较长的运行时间。另外,算法的所有性能之间都存在着或多或少的相互影响。因此,当设计一个算法(特别是大型算法)时,要综合考虑算法的各项性能,算法的使用频率,算法处理的数据量的大小,算法描述语言的特性,算法运行的机器系统环境等各方面因素,才能够设计出比较好的算法。

                                                                             常用的算法的时间复杂度和空间复杂度

     一个经验规则:其中c是一个常量,如果一个算法的复杂度为c 、 log2n 、n 、 n*log2n ,那么这个算法时间效率比较高 ,如果是2n ,3n ,n!,那么稍微大一些的n就会令这个算法不能动了,居于中间的几个则差强人意。 

讲完啦~(复制黏贴 你懂的)  (*^__^*)  

参考博客:https://blog.csdn.net/yangwei282367751/article/details/52426911?tdsourcetag=s_pctim_aiomsg

参考博客:https://blog.csdn.net/zxm490484080/article/details/72210501

猜你喜欢

转载自blog.csdn.net/henucm/article/details/82494953
今日推荐