码迷,mamicode.com
首页 > 其他好文 > 详细

尾递归和线性递归

时间:2017-05-31 23:07:12      阅读:225      评论:0      收藏:0      [点我收藏+]

标签:long   内存   特性   数据   占用   star   over   test   ack   

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循环,递推的效率是较低的,所以再不是非递推不可的环境中,尽量使用普通循环代替递归算法。

尾递归和线性递归

标签:long   内存   特性   数据   占用   star   over   test   ack   

原文地址:http://www.cnblogs.com/gongli123/p/6925278.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!