大O表示法

转载:https://blog.csdn.net/Max__Payne/article/details/1872906

一. 简介

做了几年程序,感觉基本的东西很多还不熟悉,所以重新补充数据结构知识。

1.1 大O表示法

上学的时候就学习了大O表示法表示一个算法的效率,也大概明白怎么回事,知道如果没有循环的一段程序的复杂度是常数,一层循环的复杂度是O(n),两层循环的复杂度是O(n^2)? (我用^2表示平方,同理 ^3表示立方)。但是一直对于严格的定义和用法稀里糊涂。

1.1.1 定义

设一个程序的时间复杂度用一个函数 T(n) 来表示,对于一个查找算法,如下:

这个程序是将输入的数值顺序地与数组中地元素逐个比较,找出与之相等地元素。

在第一个元素就找到需要比较一次,在第二个元素找到需要比较2次,…… ,在第n个元素找到需要比较n次。对于有n个元素的数组,如果每个元素被找到的概率相等,那么查找成功的平均比较次数为:

f(n) = 1/n (n + (n-1) + (n-2) + ... + 1) = (n+1)/2 = O(n)

这就是传说中的大O函数的原始定义。

1.1.2 用大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.1.3 加法规则

T(n,m) = T1(n) + T2(n) = O ( max (f(n), g(m) )

1.1.4 乘法规则

T(n,m) = T1(n) * T2(m) = O (f(n) * g(m))

1.1.5 一个特例

在大O表示法里面有一个特例,如果T1(n) = O(c), c是一个与n无关的任意常数,T2(n) = O ( f(n) ) 则有

T(n) = T1(n) * T2(n) = O ( c*f(n) ) = O( f(n) ).

也就是说,在大O表示法中,任何非0正常数都属于同一数量级,记为O(1)。

1.1.6 一个经验规则

有如下复杂度关系

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就会令这个算法不能动了,居于中间的几个则差强人意。

 

一、 时间复杂度定义

定义:如果一个问题的规模是n,解这一问题的某一算法所需要的时间为T(n),它是n的某一函数 T(n)称为这一算法的“时间复杂性”。

当输入量n逐渐加大时,时间复杂性的极限情形称为算法的“渐近时间复杂性”。
 

二、大O表示法

我们常用大O表示法表示时间复杂性,注意它是某一个算法的时间复杂性。大O表示只是说有上界,由定义如果f(n)=O(n),那显然成立f(n)=O(n^2),它给你一个上界,但并不是上确界,但人们在表示的时候一般都习惯表示前者。此外,一个问题本身也有它的复杂性,如果某个算法的复杂性到达了这个问题复杂性的下界,那就称这样的算法是最佳算法。
 

“大O记法”:在这种描述中使用的基本参数是 n,即问题实例的规模,把复杂性或运行时间表达为n的函数。这里的“O”表示量级 (order),比如说“二分检索是 O(logn)的”,也就是说它需要“通过logn量级的步骤去检索一个规模为n的数组”记法 O ( f(n) )表示当 n增大时,运行时间至多将以正比于 f(n)的速度增长。
 

这种渐进估计对算法的理论分析和大致比较是非常有价值的,但在实践中细节也可能造成差异。例如,一个低附加代价的O(n2)算法在n较小的情况下可能比一个高附加代价的 O(nlogn)算法运行得更快。当然,随着n足够大以后,具有较慢上升函数的算法必然工作得更快。

 

O(1)

Temp=i;i=j;j=temp;                     

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

O(n^2)

2.1. 交换i和j的内容
     sum=0;                (一次)
     for(i=1;i<=n;i++)      (n次 )
        for(j=1;j<=n;j++) (n^2次 )
          sum++;       (n^2次 )
解:T(n)=2n^2+n+1 =O(n^2)

2.2.   
    for (i=1;i     {
        y=y+1;        ①   
        for (j=0;j<=(2*n);j++)    
           x++;        ②      
    }          
解:  语句1的频度是n-1
         语句2的频度是(n-1)*(2n+1)=2n^2-n-1
          f(n)=2n^2-n-1+(n-1)=2n^2-2
         该程序的时间复杂度T(n)=O(n^2).         

O(n)      
                                                       
2.3.
    a=0;
    b=1;                     ①
    for (i=1;i<=n;i++) ②
    {  
      s=a+b;    ③
       b=a;     ④  
       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).

算法的时间复杂度(大O表示法)2

2007-06-04 13:34

 

O(log2n )

2.4.
     i=1;       ①
    while (i<=n)
       i=i*2; ②
解: 语句1的频度是1,  
         设语句2的频度是f(n),  则:2^f(n)<=n;f(n)<=log2n    
         取最大值f(n)= log2n,
          T(n)=O(log2n )

O(n^3)

2.5.
    for(i=0;i     {  
       for(j=0;j        {
          for(k=0;k              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(n^3).
                                   

我们还应该区分算法的最坏情况的行为和期望行为。如快速排序的最 坏情况运行时间是 O(n^2),但期望时间是 O(nlogn)。通过每次都仔细 地选择基准值,我们有可能把平方情况 (即O(n^2)情况)的概率减小到几乎等于 0。在实际中,精心实现的快速排序一般都能以 (O(nlogn)时间运行。

 

你可能感兴趣的:(算法)