算法的时间复杂度

常常能够在一些书上看到这种公式:程序=数据结构+算法

所以算法 的重要性是不言而喻的.




那么什么是算法呢?

算法的基本特性有:

1.确定性-----算法中的每一条指令无二义性.


2.有穷性-----算法经过有限的计算次数后结束.


3.可行性-----算法是由一些基本可行的运算实现.


4.算法有0个或者多个输入.


5.算法有1个或者多个输出.






那么我们又根据什么规则来设计一种特定的算法呢?

1.首先设计的算法要是正确的.依据严蔚敏数据结构一书中介绍了算法的这样的正确性的四个层次.

层次一:程序不含语法错误.这是最主要的,也是在刚開始学习的人最easy出现错误的地方

层次二:程序对于几组输入可以得到符合规格的结果.

层次三:程序对于精心挑选,条件苛责的输入仍然能得到符合规格的结果.这是大多数程序可以达到的层次.

层次四:程序对于不论什么输入都能得到符合规格的结果.这种程序能够称得上完美,可是要实现这种程序绝非易事.

在实际工作中,层次一往往是通过编译工具进行检查修正,否则存在语法错误的程序是无法执行的.

而后几个层次往往是使用专门的測试工具进行測试.


2.其次程序是可读的,算法不仅是面向机器,更重要的是面向读者.假设实现算法的程序是晦涩难懂的,那么这种算法肯定称不上好的算法.


3.还要程序是健壮的.所谓健壮是指实现算法的程序,不仅对于正确的输入可以给出正确的结果.对于不合要求的输入仍然可以进行错误判别.

   识别出到底是哪类错误.


4.最后就是算法时间效率和空间效率.所谓时间效率是指算法运行的时间.当然越快越好.空间效率是指算法运行所占用的内存空间.当然是越小越好.




而对于算法最重要的就是效率了,那么效率怎样度量

一种方式是将不同算法用程序实现,然后比較执行时间.这是一种最直观的比較算法效率的方法.非常明显这样的方式要求我们

将要比較的算法首先一一实现之后再来进行比較.不难看出这样的比較方式是比較笨拙的.并且不同的硬件条件下执行的时间

也肯定是有差异的.

二种方式是不须要事先将算法实现来计算算法的时间效率:

这样的方式须要考虑例如以下几个方面的因素:1.问题的规模.比方计算100的阶乘肯定和计算1000的阶乘肯定执行时间不同.100和1000就是规模

     2.书写算法的程序语言越高低,时间效率越低.反之,效率越高.

     3.代码本身的质量,是否有冗余代码等等

     4.计算机指令运行的快慢.





我们撇开语言,代码质量,硬件质量快慢这些觉得可控因素不谈.

同一算法的时间效率主要取决于问题规模的大小.






对于同一问题的不同算法,在同样的问题规模下:

我们以100的累加为例.

计算100的阶乘,能够是1+2+3+4+5......100

    也能够是(1+100)+(2+99)+(3+98)+......+(50+51)即简化为101*50;

非常显然另外一种计算方法要便于计算,时间效率高于第一种.


接下来我们将上例用代码进行描写叙述:

第一种方式的累加
int sum=0;  	①
for(int i=1;i<=100;i++)   ②
	sum=sum+i;	③

另外一种方式的累加
int sum=0;	①
for(int i=1,j=101;i<=50&&j>=51;j--,i++)②
	sum=sum+i+j;③

我们将算法的时间效率用算法中基本指令运行的次数来描写叙述.不差别不同基本指令运行时间的差异.

第一种方式的累加:

①中int sum=0;运行的1次

②中 int i=0运行1次;i<=100;i++分别运行了100次

③中sum=sum+i运行了100次

所以总共的次数为 1+1+2*100+100=302;


另外一种方式的累加:

①中int sun=0运行了1次

②中int i=0运行了1次,i<=50&&j>=51;j--,i++分别运行了50次

③中sum=sum+i+j运行了50次

所以总共的次数为 1+1+2*50+50=152;

非常显然如果每条指令运行的时间同样那么方式二的累加是不是例如式一的累加省了非常多时间呢.









这里我们引入时间频度T(n)的概念.T(n)为实现一种算法的指令运行的次数(n为问题规模).

那么两种方式分别为:T1(n)=2*n+n+2=3n+2

T2(n)=2*(n/2)+n/2+2=3n/2+2


我们用渐进时间复杂度来对时间频道进行描写叙述,简称时间复杂度.

渐进时间复杂度即存在f(n)使得当n-->无限大 有lim(T(n)/f(n))=C(常数).

那么O(f(n))即为该算法的时间复杂度.T(n)=O(f(n));

非常明显T1(n),T2(n)时间复杂度均为O(n);







那么详细怎样计算时间复杂度呢?

比方N*N矩阵相乘:

代码例如以下:

int i,j,k;		①
for(i=1;i<=n;i++)	 ②
   for(j=1;j<=n;j++)	③
{
      c[i][j]=0;	④
	for(k=1;k<=n;k++)  ⑤
	    c[i][j]+=a[i][k]*b[k][j];⑥
}
当中

①中语句运行1次

②中i=1运行一次,剩下的均运行n次

③中j=1运行n次;剩下的均运行n^2次

④中语句运行n^2次

⑤中k=1运行n^2次,剩下的均运行n^3次

⑥中语句运行n^3次

所以T(n)=1+1+2*n+n+2*n^2+n^2+n^2+2*n^3=2+3n+4n^2+3n^3

非常显然当f(n)=cn^3时候 lim(T(n/f(n)))=常数 故时间复杂度为O(n^3);








可是O(n^3)的复杂度是好还是不好呢.

依据经验-推断:

普通情况下可依据此规则推断一个算法的复杂度的优劣:

c < log2n < n < n*log2n < n2 < n3 < 2n < 3n < n! (c是一个常量)
|--------------------------|--------------------------|-------------|
          较好                     一般              较差
当中c是一个常量。假设一个算法的复杂度为c 、 log2n 、n 、 n*log2n,那么这个算法时间效率比較高 

假设是 2n , 3n ,n!,那么略微大一些的n就会令这个算法不能动了,居于中间的几个则差强人意。








最后补充一些知识:

1计算规则

若T1(n)=O(f1(n)),T2(m)=O(f2(m));

加法规则:

则T(m,n)=T(m)+T(n)=O(max(f1(n),f2(m)))

乘法规则

则T(m,n)=T(m)*T(n)=O(f1(n)*f2(m))

常数可去掉

T1(m)=O(f(m))  T2(m)=O(c*f(m))

T(m)=T1(m)=T2(m)=O(f(m))


2.关于最坏复杂度

某些情况下同一算法的时间复杂度不仅和输入规模有关还与输入顺序有关.

这样的情况下我们计算其最坏情况下的时间复杂度来度量算法的时间效率.









本文究竟就对算法的时间复杂度介绍完了,文中难免出现错误,望读者批评指正.



转载请注明作者:小刘



posted on 2017-04-14 20:44  blfbuaa  阅读(874)  评论(0编辑  收藏  举报