首页 > 分享 > 递归算法的时间复杂度分析

递归算法的时间复杂度分析

 在算法分析中,当一个算法中包含递归调用时,其时间复杂度的分析会转化为一个递归方程求解。实际上,这个问题是数学上求解渐近阶的问题,而递归方程的形式多种多样,其求解方法也是不一而足,比较常用的有以下四种方法:

    (1)代入法(Substitution Method)

         代入法的基本步骤是先推测递归方程的显式解,然后用数学归纳法来验证该解是否合理。

         (2)迭代法(Iteration Method)

         迭代法的基本步骤是迭代地展开递归方程的右端,使之成为一个非递归的和式,然后通过对和式的估计来达到对方程左端即方程的解的估计。

         (3)套用公式法(Master Method)

         这个方法针对形如“T(n) = aT(n/b) + f(n)”的递归方程。这种递归方程是分治法的时间复杂性所满足的递归关系,即一个规模为n的问题被分成规模均为n/b的a个子问题,递归地求解这a个子 问题,然后通过对这a个子间题的解的综合,得到原问题的解。

         (4)差分方程法(Difference Formula Method)

    可以将某些递归方程看成差分方程,通过解差分方程的方法来解递归方程,然后对解作出渐近阶估计。

         下面就以上方法给出一些例子说明。

             一、代入法

         大整数乘法计算时间的递归方程为:T(n) = 4T(n/2) + O(n),其中T(1) = O(1),我们猜测一个解T(n) = O(n2 ),根据符号O的定义,对n>n0,有T(n) < cn2 - eO(2n)(注意,这里减去O(2n),因其是低阶项,不会影响到n足够大时的渐近性),把这个解代入递归方程,得到:

         T(n) =  4T(n/2) + O(n)
           ≤ 4c(n/2)2 - eO(2n/2)) + O(n)
           =  cn2 - eO(n) + O(n)
           ≤ cn2

         其中,c为正常数,e取1,上式符合 T(n)≤cn2 的定义,则可认为O(n2 )是T(n)的一个解,再用数学归纳法加以证明。

         二、迭代法

    某算法的计算时间为:T(n) = 3T(n/4) + O(n),其中T(1) = O(1),迭代两次可将右端展开为:

         T(n) = 3T(n/4) + O(n)
         = O(n) + 3( O(n/4) + 3T(n/42 ) )
         = O(n) + 3( O(n/4) + 3( O(n/42 ) + 3T(n/43 ) ) )

              从上式可以看出,这是一个递归方程,我们可以写出迭代i次后的方程:

         T(n) = O(n) + 3( O(n/4) + 3( O(n/42 ) + ... + 3( n/4i + 3T(n/4i+1 ) ) ) )

         当n/4i+1 =1时,T(n/4i+1 )=1,则

         T(n) = n + (3/4) + (32 /42 )n + ... + (3i /4i )n + (3i+1 )T(1)
         < 4n + 3i+1

              而由n/4i+1 =1可知,i<log4 n,从而

         3i+1 ≤ 3log4 n+1 = 3log3 n*log4 3 +1 = 3nlog4 3

         代入得:

         T(n) < 4n + 3nlog4 3,即T(n) = O(n)。

         三、套用公式法

         这个方法为估计形如:

  T(n) = aT(n/b) + f(n)

  其中,a≥1和b≥1,均为常数,f(n)是一个确定的正函数。在f(n)的三类情况下,我们有T(n)的渐近估计式:

    1.若对于某常数ε>0,有f(n) = O(nlogb a-ε ),则T(n) = O(nlogb a )

         2.若f(n) = O(nlogb a ),则T(n) = O(nlogb a *logn)

         3.若f(n) = O(nlogb a+ε ),且对于某常数c>1和所有充分大的正整数n,有af(n/b)≤cf(n),则T(n)=O(f(n))。

         设T(n) = 4T(n/2) + n,则a = 4,b = 2,f(n) = n,计算得出nlogb a = nlog2 4 = n2 ,而f(n) = n = O(n2-ε ),此时ε= 1,根据第1种情况,我们得到T(n) = O(n2 )。

         这里涉及的三类情况,都是拿f(n)与nlogb a 作比较,而递归方程解的渐近阶由这两个函数中的较大者决定。在第一类情况下,函数nlogb a 较大,则T(n)=O(nlogb a );在第三类情况下,函数f(n)较大,则T(n)=O(f (n));在第二类情况下,两个函数一样大,则T(n)=O(nlogb a *logn),即以n的对数作为因子乘上f(n)与T(n)的同阶。

         但上述三类情况并没有覆盖所有可能的f(n)。在第一类情况和第二类情况之间有一个间隙:f(n)小于但不是多项式地小于nlogb a ,第二类与第三类之间也存在这种情况,此时公式法不适用。

二 

  递归函数时间复杂度分析

(1) 递归执行过程 
   例子:求N!。 
    这是一个简单的"累乘"问题,用递归算法也能解决。 
    n! = n * (n - 1)!   n > 1 
    0! = 1, 1! = 1      n = 0,1 
    因此,递归算法如下: 
   
Java代码 
fact(int n) {  
    if(n == 0 || n == 1)   
         return 1;  
        else   
             return n * fact(n - 1);  
    }  
    以n=3为例,看运行过程如下: 
    fact(3) ----- fact(2) ----- fact(1) ------ fact(2) -----fact(3) 
    ------------------------------>  ------------------------------> 
                递归                            回溯 
  递归算法在运行中不断调用自身降低规模的过程,当规模降为1,即递归到fact(1)时,满足停止条件停止递归,开始回溯(返回调用算法)并计算,从fact(1)=1计算返回到fact(2);计算2*fact(1)=2返回到fact(3);计算3*fact(2)=6,结束递归。 
   算法的起始模块也是终止模块。 
(2) 递归实现机制 
    每一次递归调用,都用一个特殊的数据结构"栈"记录当前算法的执行状态,特别地设置地址栈,用来记录当前算法的执行位置,以备回溯时正常返回。递归模块的形式参数是普通变量,每次递归调用得到的值都是不同的,他们也是由"栈"来存储。 
(3) 递归调用的几种形式 
    一般递归调用有以下几种形式(其中a1、a2、b1、b2、k1、k2为常数)。 
   <1> 直接简单递归调用: f(n) {...a1 * f((n - k1) / b1); ...}; 
    
   <2> 直接复杂递归调用: f(n) {...a1 * f((n - k1) / b1); a2 * f((n - k2) / b2); ...}; 
    <3> 间接递归调用:  f(n) {...a1 * f((n - k1) / b1); ...}, 
                        g(n) {...a2 * f((n - k2) / b2); ...}。 
2. 递归算法效率分析方法 
   递归算法的分析方法比较多,最常用的便是迭代法。 
  迭代法的基本步骤是先将递归算法简化为对应的递归方程,然后通过反复迭代,将递归方程的右端变换成一个级数,最后求级数的和,再估计和的渐进阶。 
  <1> 例:n! 
       算法的递归方程为: T(n) = T(n - 1) + O(1); 
       迭代展开: T(n) = T(n - 1) + O(1) 
                       = T(n - 2) + O(1) + O(1) 
                       = T(n - 3) + O(1) + O(1) + O(1) 
                       = ...... 
                       = O(1) + ... + O(1) + O(1) + O(1) 
                       = n * O(1) 
                       = O(n) 
      这个例子的时间复杂性是线性的。 
<2> 例:如下递归方程: 
      
      T(n) = 2T(n/2) + 2, 且假设n=2的k次方。 
      T(n) = 2T(n/2) + 2 
           = 2(2T(n/2*2) + 2) + 2 
           = 4T(n/2*2) + 4 + 2 
           = 4(2T(n/2*2*2) + 2) + 4 + 2 
           = 2*2*2T(n/2*2*2) + 8 + 4 + 2 
           = ... 
           = 2的(k-1)次方 * T(n/2的(i-1)次方) + $(i:1~(k-1))2的i次方 
           = 2的(k-1)次方 + (2的k次方)  - 2 
           = (3/2) * (2的k次方) - 2 
           = (3/2) * n - 2 
           = O(n) 
      这个例子的时间复杂性也是线性的。 
<3> 例:如下递归方程: 
      
      T(n) = 2T(n/2) + O(n), 且假设n=2的k次方。 
      T(n) = 2T(n/2) + O(n) 
           = 2T(n/4) + 2O(n/2) + O(n) 
           = ... 
           = O(n) + O(n) + ... + O(n) + O(n) + O(n) 
           = k * O(n) 
           = O(k*n) 
           = O(nlog2n) //以2为底 
     
      一般地,当递归方程为T(n) = aT(n/c) + O(n), T(n)的解为: 
      O(n)          (a<c && c>1) 
      O(nlog2n)     (a=c && c>1) //以2为底 
      O(nlogca)     (a>c && c>1) //n的(logca)次方,以c为底 
   上面介绍的3种递归调用形式,比较常用的是第一种情况,第二种形式也有时出现,而第三种形式(间接递归调用)使用的较少,且算法分析 
比较复杂。 下面举个第二种形式的递归调用例子。 
  <4> 递归方程为:T(n) = T(n/3) + T(2n/3) + n 
     为了更好的理解,先画出递归过程相应的递归树: 
                            n                        --------> n 
                    n/3            2n/3              --------> n 
              n/9       2n/9   2n/9     4n/9         --------> n 
           ......     ......  ......  .......        ...... 
                                                     -------- 
                                                     总共O(nlogn) 
     累计递归树各层的非递归项的值,每一层和都等于n,从根到叶的最长路径是: 
    
      n --> (2/3)n --> (4/9)n --> (12/27)n --> ... --> 1 
     设最长路径为k,则应该有: 
      
     (2/3)的k次方 * n = 1 
     得到 k = log(2/3)n  // 以(2/3)为底 
     于是 T(n) <= (K + 1) * n = n (log(2/3)n + 1) 
     即 T(n) = O(nlogn) 
    由此例子表明,对于第二种递归形式调用,借助于递归树,用迭代法进行算法分析是简单易行的。





 

递归算法的时间复杂度总结

很多算法都使用到了递归的方法,或者说递归的思想,即把一个问题划分成同样的小规模的问题,然后再解决,动态规划,分而治之都是,递归算法的时间复杂度也有规律可循。

针对T(n) = aT(n/b) + f(n)这类递归,有以下规定

最后一段说的比较明白,这个定理记不住,但是一些非常典型的例子可以记住:

1.T(n)=2T(n/2)  和 T(n)=2T(n/2) +k

例子有 二叉树的递归遍历

时间复杂度 T(n)=O(n)

2.T(n)=2T(n/2)+kn+j

例子有 快速排序

时间复杂度为 T(n)=O(nlogn)

3.T(n)=T(n/2)+kn+j

例子有 二叉树最近公共祖先

时间复杂度为T(n)=O(n)

最后对应T(N)=T(N-1)+T(N-2)

运行时间最大是T(N)》(3/2)^N,因此运行时间以指数速度增长。


相关知识

分析以下各程序段的时间复杂度。 分析以下程序段的时间复杂度。 ... i=1;
云计算下分布式数据安全读取算法研究.pdf资源
ID3算法(含实例)
I am here! QwQ
蚁群算法+Dijkstra算法=二维路径规划,基于蚁群算法的机器人路径规划,matlab源码.rar资源
基于自相关分析的动物活动模式判别算法研究
智能优化算法改进三个定性分析实验:收敛行为分析,种群多样性分析和探索开发分析
NOIP初赛知识
基于JAVA协同过滤算法网上宠物用品推荐购物商城系统设计与实现(Springboot框架)可行性分析
面向宠粮生产的多目标蚱蜢算法优化及应用

网址: 递归算法的时间复杂度分析 https://m.mcbbbk.com/newsview319485.html

所属分类:萌宠日常
上一篇: 【司法动态】城管+律师=?“律师
下一篇: 蹬三轮助学老人白芳礼落选感动中国