简单来说,递归即是调用自己本身。所有递归都应该有至少一个基本条件,在满足基本条件时不进行递归。

给出一个递归实例:

 int fact(int N){
if(N==1)
return 1;
else
return N*fact(N-1);
}

每一个递归方法的执行都分为前进和回退两个阶段,上例中计算5的阶乘,前进阶段得到的结果是:

(5*(4*(3*(2*(1)))))

回退阶段则由内向外,依次计算括号中的值。

应用到程序中,分别对应压栈和出栈。考虑到这种做法,每次调用都会压栈出栈,效率很低。除此之外,每次递归创建新的栈在递归深度过深的时候,会引起栈溢出,也就是可以分给创建栈的内存不足的情况。尾递归的方法由此提出。

尾递归,简单来说,就是将递归语句写到最后一行且不参与任何计算。本质上,每次递归将接受上一次递归的传参,并将本次计算结果传给下一次递归,当递归到达终结条件的时候,其计算值即为返回值。这样相比普通递归,省去了递归的回退过程,也即不用再回退到上一次递归作运算,自然就省去了很多创建栈、压栈与出栈的工作,性能得到提升。将上例改写为尾递归为:

 int fact(int N){
if(N==1)
return 1;
else
return fact(N-1,N);
} int fact(int N, int M){
if(N==1)
return M;
else
return fact(N-1, N*M);
}

这是有外及里的尾递归,当计算斐波那契数列的时候就要换一种思路,即由里及外。

斐波那契问题描述:每个兔子出生后的第三个月后,每个月都可以生下一对兔子,如果不考虑兔子死亡问题,第一个月有新出生的一对兔子,那第N个月有多少兔子?

其尾递归代码如下:

 int Fibonacci(int N, int first, int second, int begin){
if(begin>=N)
return first;
else
return Fibonacci(N, second, first+second, begin+1);
}

但这要求编译器能对尾递归进行优化,每次重用或者说覆盖原来递归方法的栈,而不是新建栈。遗憾的是JAVA和python都不支持尾递归的优化,JAVA的尾递归代码与普通递归无异。可能JVM是想在出现异常时更好地输出堆栈信息的缘故。所以,JAVA中一般能用迭代就不用递归。

尾递归和JAVA的更多相关文章

  1. 尾递归(java)

    一般递归: 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多 ...

  2. Spark案例分析

    一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...

  3. 【Java】斐波那契数列(Fibonacci Sequence、兔子数列)的3种计算方法(递归实现、递归值缓存实现、循环实现、尾递归实现)

    斐波那契数列:0.1.1.2.3.5.8.13………… 他的规律是,第一项是0,第二项是1,第三项开始(含第三项)等于前两项之和. > 递归实现 看到这个规则,第一个想起当然是递归算法去实现了, ...

  4. 在Java中谈尾递归--尾递归和垃圾回收的比较(转载)

    我不是故意在JAVA中谈尾递归的,因为在JAVA中谈尾递归真的是要绕好几个弯,只是我确实只有JAVA学得比较好,虽然确实C是在学校学过还考了90+,真学得没自学的JAVA好 不过也是因为要绕几个弯,所 ...

  5. Java中谈尾递归--尾递归和垃圾回收的比较

    一.首先我们讲讲递归 1.递归的本质是,某个方法中调用了自身,本质还是调用了一个方法,只是这个方法正好是自身而已 2.递归因为是在自身中调用自身,所以会带来以下三个显著特点:    1.调用的是同一个 ...

  6. 在Java中谈尾递归--尾递归和垃圾回收的比较

    我不是故意在JAVA中谈尾递归的,因为在JAVA中谈尾递归真的是要绕好几个弯,只是我确实只有JAVA学得比较好,虽然确实C是在学校学过还考了90+,真学得没自学的JAVA好 不过也是因为要绕几个弯,所 ...

  7. Java8函数之旅 (六) -- 使用lambda实现Java的尾递归

    前言 本篇介绍的不是什么新知识,而是对前面讲解的一些知识的综合运用.众所周知,递归是解决复杂问题的一个很有效的方式,也是函数式语言的核心,在一些函数式语言中,是没有迭代与while这种概念的,因为此类 ...

  8. [Java 8] (8) Lambda表达式对递归的优化(上) - 使用尾递归 .

    递归优化 很多算法都依赖于递归,典型的比如分治法(Divide-and-Conquer).但是普通的递归算法在处理规模较大的问题时,常常会出现StackOverflowError.处理这个问题,我们可 ...

  9. Java 递归、尾递归、非递归、栈 处理 三角数问题

    import java.io.BufferedReader; import java.io.InputStreamReader; //1,3,6,10,15...n 三角数 /* * # 1 * ## ...

随机推荐

  1. python快速入门基础知识

    1.变量赋值与语句 #python 不需要手动指定变量类型.不需要分号 #To assign the value 365 to the variable days,we enter the varia ...

  2. OpenCV-Python 形态学转换 | 十七

    目标 在这一章当中, 我们将学习不同的形态学操作,例如侵蚀,膨胀,开运算,闭运算等. 我们将看到不同的功能,例如:cv.erode(),cv.dilate(), cv.morphologyEx()等. ...

  3. 使用Python创建自己的Instagram滤镜

    不知道你有没有使用过Instagram滤镜,它们非常方便,只需单击几个按钮,就可以变换我要发布的照片​​. 你是否想过自己可以创建一个?答案是可以的! 在本文中,我将向你展示如何使用代码和示例图像来创 ...

  4. php _weakup()反序列化漏洞

    概念&原理 序列化就是使用 serialize() 将对象用字符串的方式进行表示: 反序列化是使用 unserialize() 将序列化的字符串构造成相应的对象,为序列化的逆过程. 序列化的对 ...

  5. ubuntu 如何在命令行打开当前目录

    nautilus /var 打开var文件夹

  6. logstash用jdbc插件将数据库内容导入elasticsearch时间字段相差5小时

    logstash将mysql的数据导入elasticsearch之后发现时间字段的相差5个小时 解决办法: 在数据库连接配置后面加上?serverTimezone=UCT这个就OK了 logstash ...

  7. 六、【Docker笔记】Docker数据管理

    前几节我们介绍了Docker的基本使用和三大核心概念,那么我们在使用Docker的过程中,Docker中必然产生了大量的数据,对于这些数据我们需要查看或者对这些数据进行一个备份,也有可能容器之间的数据 ...

  8. 写给程序员的机器学习入门 (二) - pytorch 与矩阵计算入门

    pytorch 简介 pytorch 是目前世界上最流行的两个机器学习框架的其中之一,与 tensoflow 并峙双雄.它提供了很多方便的功能,例如根据损失自动微分计算应该怎样调整参数,提供了一系列的 ...

  9. Pyhton基本图形绘制

    目前学习Python中,记录一些内容~ 以下为部分练习内容 1.Python蟒蛇绘制 1 #PythonDraw.py 2 import turtle as t #t作为turtle的别名:另一种方法 ...

  10. Java内存可见性volatile

    概述 JMM规范指出,每一个线程都有自己的工作内存(working memory),当变量的值发生变化时,先更新自己的工作内存,然后再拷贝到主存(main memory),这样其他线程就能读取到更新后 ...