算法的时间复杂度

来源:互联网 发布:java正则判断是否数字 编辑:程序博客网 时间:2024/05/02 01:45

在计算算法复杂度时一般只用到大O符号,Landau符号体系中的小o符号、Θ符号等等比较不常用。这f (n) = Ο(g (n)) 表示存在一个常数C,使得在当n趋于正无穷时总有 f (n) ≤ C * g(n)。   

例如,O(2n^2+n +1) = O (3n^2+n+3) = O (7n^2 + n) = O ( n^2 ) ,一般都只用O(n^2)表示就可以了。注意到大O符号里隐藏着一个常数C,所以g(n)里一般不加系数。如果把f(n)当做一棵树,那么O(g(n))所表达的就是树干,只关心其中的主干,其他的细枝末节全都抛弃不管。

O(1) O(log n) O(n), O(n * log n) ,O(n^k) O(a^n), O(n!)越往后,复杂度越大

复杂度举例:

(1) O(1) 常数级复杂度,也就是说程序运行的时间与需要处理的数据大小无关。通常把比较大小、加减乘除等简单的运算都当做常数级复杂度。

(2) O(logn) 将一个10进制整数转化为2进制整数lnn,lgn对数O(logn)常底数是无所谓的的,因为有换底公式   ,因为a,b都是常数,所以对于对数一般不需要注明底数,所以不用纠结底数到底是2还是10啦,因为无所谓啦……常数次幂也是无所谓的啦,因为有

(3) O(n):判断一个元素是否属于一个大小为n的集合/列表;找出n个数中的最大值;

(4)O(n * log n) 快速排序法

(5) O(n^2) 最直白的两两比较然后排序方法,需要n*(n-1)/2次比较,所以是O(n^2)级。

(6) O(2^n) 列出所有长度为n的0,1字符串之类的穷举计算

(7)O(n!) 列出n个元素的全排列之类的穷举计算

复杂度与时间效率的关系:
c < logn < n < n*logn < n2 < n3 < 2n < 3n < n! (c是一个常量)
|--------------------------|--------------------------|-------------|
          较好                    一般             较差
其中c是一个常量,如果一个算法的复杂度为c 、 logn 、n 、 n*logn,那么这个算法时间效率比较高,如果是 2n , 3n ,n!,那么稍微大一些的n就会令这个算法不能动了,居于中间的几个则差强人意。

一个算法,对于一个规模是n的输入,需要T(n)的时间进行运算。T(n)的具体值,一方面取决于算法,另一方面和计算用的工具也有关。但我们关心的是,当n扩大100倍以后,T(n)是几乎不变,还是扩大了100倍、10000倍或者怎样。我们关心的是规模扩大后,运算时间增长得有多快,是一个相对的结果,而不是绝对结果。

建立一个空列表,需要的时间总是固定的,就是O(1);如果有一句for或者while的语句,把同一行代码运算了n次,那么就是O(n)级的复杂度;如果for下面还有for,各自要算n次,那么就是n^2的复杂度,以此类推。

常用计算:

算数级数:T(n)=1+2+3+4…+n=n(n+1)/2=O(n2),算数级数的是和末项平方同阶;

幂方级数:T2(n)=12+22+32+…+n2=O(n3),T3(n)=O(n4),阶数是(幂方+1)的级数;

几何级数:Ta(n)=a0+a1+a2+…+an=O(an),与末项同阶;

收敛级数:

1+1/2^2+1/3^2+1/4^2+…=O(1)

例如:

(1)T(n)=T(n-1)+O(n)时间复杂度是O(n^2)

T(n-1) = T(n-2) + O(n-1)…

所以T(n) =O(n) + O(n-1) + O(n-2) +…+ O(1) + T(0)
这个T(0)一般为某个常数,前面的加起来是O(n(n+1)/2),也就是O(n^2)。

(2)T(n)=T(n/2)+O(1)= O()=O(logn)分治算法,底数是无所谓的。

 

利用实例来分析不同算法的不同时间复杂度对程序的影响:

斐波那契数列:

一开始有一对小兔子。小兔子需要一个月以后才能长成大兔子从而拥有生育能力;所有拥有生育能力的大兔子每个月都会生一对小兔子。所有的兔子都长生不老,问第n个月一共有多少兔子呢?

观察规律得到:

月份

1

2

3

4

5

6

7

兔/只

1

1

2

3

5

8

13

规律是F(n)=F(n-1)+F(n-2);

(1)很容易想到的算法,指数级复杂度;O(2^n),效率太低了

 

intF[1]=1,F[2]=1;

if(n<3)

sum=1;

else

sum=F[n-1]+F[n-2];

return sum;


(2)for语句,循环n-2次,O(n)级的复杂度,相比第一次的算法这次要简单得多(每一步都有保存数据,消耗空间复杂度以获得较好的时间复杂度。)

int x=1;y=1;

for(int i=2;i<n;i++)

{

    temp=x;

    x=y;

y=x+temp;

}

 (3) 矩阵乘方,复杂度是O(log n),速度很快

由此,我们求一个矩阵的n次方即可。两个2维矩阵的乘法次数可以看作常量。矩阵n次方利用分治法,只需要O(logn)的复杂度就能计算出来.算法代码如下:

staticintFibonacci3(intn)

{

    int[,]a=newint[2,2]{{1,1},{1,0}};

    int[,]b=MatirxClub(a,n);

    returnb[1,0];

}

 

staticint[,]MatirxClub(int[,]a,intn)

{

    if(n==1){returna;}

    elseif(n==2){returnMatirx(a,a);}

    elseif(n%2==0)

    {

       int[,]temp=MatirxClub(a,n/2);

       returnMatirx(temp,temp);

    }

    else

    {

       int[,]temp=MatirxClub(a,n/2);

       returnMatirx(Matirx(temp,temp),a);

    }

}

 

staticint[,]Matirx(int[,]a,int[,]b)

{

    int[,]c=newint[2,2];

    for(inti=0;i<2;i++)

    {

       for(intj=0;j<2;j++)

       {

           for(intk=0;k<2;k++)

           {

                c[i,j]+=a[i,k]*b[k,j];

           }

       }

    }

    returnc;

}

 

 

0 0
原创粉丝点击