zoukankan      html  css  js  c++  java
  • 尾递归和线性递归

    1、递归的定义

    • 函数直接或间接的调用自己
    • 使用递归时,必须有明确的结束递归的条件

    2、递归的适用场合

    • 数据的定义按照递归定义(比如求n!)
    • 问题的解法适用于使用递归
    • 数据的结构是按递归定义的(比如二叉树)

    3、线性递归

      也就是普通递归,下一次递归数据的计算要依赖于上一次递归的结果和参数,当数据量较小时执行效率与尾递归几乎没区别,但当数据量较大,迭代次数较多时,由于每次递归都要在内存中开辟一个栈空间,用来存储上次递归的结果和参数,这样的算法将导致严重的内存开销,甚至造成内存溢出,抛出java.lang.StackOverflowError,下面用线性递归实现斐波那契数列。

      /**

    * 线性递归实现斐波拉契数列

    * @param month

    */

    public  int fblq(int month){

    if(month<3){

    return 1;

    }

    return fblq(month-1)+fblq(month-2);//每步递归都严重依赖上一次递归结果,并占用大量的栈区空间,执行效率极低

    }

    测试上段程序运行时间

    @Test

    public  void test(){

    long startTime = System.currentTimeMillis();

    System.out.println(fblq(50));

    long endTime = System.currentTimeMillis();

    System.out.println("程序运行时间:" + (endTime - startTime) + "ms");    //输出程序运行时间

    }

       程序运行时间:43643ms(非常慢),递归所需栈区空间,以指数级进行增长

    4、尾递归

      如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个函数是尾递归的。尾递归函数的特点是在回归过程中不用做任何操作,这个特性很重要,因为大多数现代的编译器会利用这种特点自动生成优化的代码。

    /**
    * 斐波那契数列尾递归
    */
    public int fblq(int n,int num1,int num2){
    if(n==1){
    return num1;
    }
    return fblq(n-1,num2,num1+num2);
    }

    @Test
    public void Test37(){
    long startTime = System.currentTimeMillis();
    System.out.println(fblq(50,1,1));
    long endTime = System.currentTimeMillis();
    System.out.println("程序运行时间:" + (endTime - startTime) + "ms"); //输出程序运行时间
    }

    程序运行时间:1ms,递归以线性关系增长

    总结:在能使用尾递归时尽量使用尾递归,这样不仅能节省内存资源,而且执行效率更高,但是相比于普通for循环,递归的效率是较低的,所以再不是非递归不可的环境中,尽量使用普通循环代替递归算法。

    希望各位大神,对文中的不足不吝赐教,共同学习,共同进步!!!
  • 相关阅读:
    多态性的理解
    类(三)——继承与多态
    类(二)——拷贝控制(浅拷贝,深拷贝,浅赋值,深赋值)
    类 (一) ——基本概念
    STL容器底层数据结构的实现
    异常处理
    C++实现单例模式
    类的成员函数的连续调用与返回值问题
    拷贝构造函数的参数为什么必须使用引用类型?拷贝赋值运算符的参数为什么也是引用类型?
    U盘装机教程
  • 原文地址:https://www.cnblogs.com/gongli123/p/6925278.html
Copyright © 2011-2022 走看看