• 关于递归的理解及递归表达式复杂度分析(以求解最大公约数为例)


    一,递归的四大基本法则:

    ①基准情形

    基准情形是指那些不需要递归(不需要经过函数调用)之后就能退出的情况。它保证了递归的结束。

    ②不断推进

    每一次递归之后,都要向着基准情形靠近,并且在靠近的过程中问题的规模越来越小。

    ③设计法则

    书上说是:假设所有的递归调用都能运行-----“不是特别理解”

    ④合成效益法则

    不要在不同的递归调用中做重复的工作。

    二,实例

    求解最大公约数--采用欧几里德算法

     1 public static int gcd_recursive(int m, int n){
     2         if(m < n)
     3         {
     4             int tmp = m;
     5             m = n;
     6             n = tmp;
     7         }
     8         
     9         if(n == 0)
    10             return m;//基准条件
    11         return gcd_recursive(n, m%n);//不断推进
    12     }

    分析:

    第9-10行,是递归的基准条件。如果n=0,函数执行到10返回,不会执行到11行进行递归调用。

    第11行,进行递归调用的地方。它是不断推进的,因为递归调用的参数朝着基准条件的方向变小了,如:

    gcd_recursive(16,12)---->gcd_recursive(12,4)--->gcd_recursive(4,0)

    每次递归调用,问题的规模越来越小了。

    时间复杂度分析:

    由公式: m%n<=m/2  可知:每次递归调用,问题的规模减小一半,类似于二分查找,这显然是一个非常好的算法。

    由于第2-5行,花费的时间为常量时间,同样,在第9-10行的if语句判断也是花费的常量时间,在第11行进行递归调用,问题规模减少一半。

    可得出,T(N) = T(N/2)+O(1)  推出:时间复杂度为O(logN)

    -------------------------------------------------------------

    递归逻辑的分析:

    对于 gcd_recursive(16,12),第9行不成立,进入到第11行递归

    对于 gcd_recursive(12,4), 第9行不成立,进入到第11行递归

    对于gcd_recursive(4,0),直接执行到第9行返回,返回的值是4

    返回之后,程序此时执行到gcd_recursive(12,4)中的第11行(即最后一行,不要被第9行干扰!第9行在gcd_recursive(12,4)中根本没有执行!!)

    第11行代码是:gcd_recursive(4,0)

    因为,gcd_recursive(4,0) 的结果是4,故 return gcd_recursive(4,0) 返回的结果也是 4。也即gcd_recursive(12,4)执行完成之后返回4。

    由上面gcd_recursive(12,4)执行完成之后返回4,那么当gcd_recursive(16,12)的第11行代码 return gcd_recursive(12,4) 

    执行完毕时,

    整个程序结束了,返回的结果最终是4。

    这种形式的递归又称为尾递归。可以看出,尾递归形式的程序最终返回的值就是 最里层递归调用得到的值。

    在这篇文章中:字符数组转换成数字

    递归的时间复杂度分析如下:

    return recurse(c, len - 1) * 10 + (c[len - 1] - '0');

    使得每次递归时,问题规模减小1,而后面的 + (c[len - 1] - '0') 操作可视为常量时间,故复杂度:

    T(N) = T(N-1)+O(1)  得到T(N)=O(N)

    结论:

    对于递归操作而言,如果每次递归使问题的规模减半,而其他操作都是常数时间

    T(N)=T(N/2)+O(1), 则T(N)=O(logN)

    若每次递归使用问题的规模减1,而其他操作是常数时间

    T(N)=T(N-1)+O(1),则T(N)=O(N)

    若每次递归使问题的规模减半,而其他操作是线性时间,T(N) = T(N/2)+O(N)

    则T(N)=O(NlogN)

  • 相关阅读:
    CDN用户访问调度流程
    最近复习原型 终于明白了一点 写下原型相对比较完美的一种继承方式
    flex布局学习
    Vuex基本使用
    Promise的基本使用
    创建对象的几种方式
    父访问子的数据方法
    购物车案例
    插槽的使用
    ref获取DOM元素
  • 原文地址:https://www.cnblogs.com/hapjin/p/5369881.html
Copyright © 2020-2023  润新知