尾递归和JAVA
简单来说,递归即是调用自己本身。所有递归都应该有至少一个基本条件,在满足基本条件时不进行递归。
给出一个递归实例:
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的更多相关文章
- 尾递归(java)
一般递归: 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多 ...
- Spark案例分析
一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...
- 【Java】斐波那契数列(Fibonacci Sequence、兔子数列)的3种计算方法(递归实现、递归值缓存实现、循环实现、尾递归实现)
斐波那契数列:0.1.1.2.3.5.8.13………… 他的规律是,第一项是0,第二项是1,第三项开始(含第三项)等于前两项之和. > 递归实现 看到这个规则,第一个想起当然是递归算法去实现了, ...
- 在Java中谈尾递归--尾递归和垃圾回收的比较(转载)
我不是故意在JAVA中谈尾递归的,因为在JAVA中谈尾递归真的是要绕好几个弯,只是我确实只有JAVA学得比较好,虽然确实C是在学校学过还考了90+,真学得没自学的JAVA好 不过也是因为要绕几个弯,所 ...
- Java中谈尾递归--尾递归和垃圾回收的比较
一.首先我们讲讲递归 1.递归的本质是,某个方法中调用了自身,本质还是调用了一个方法,只是这个方法正好是自身而已 2.递归因为是在自身中调用自身,所以会带来以下三个显著特点: 1.调用的是同一个 ...
- 在Java中谈尾递归--尾递归和垃圾回收的比较
我不是故意在JAVA中谈尾递归的,因为在JAVA中谈尾递归真的是要绕好几个弯,只是我确实只有JAVA学得比较好,虽然确实C是在学校学过还考了90+,真学得没自学的JAVA好 不过也是因为要绕几个弯,所 ...
- Java8函数之旅 (六) -- 使用lambda实现Java的尾递归
前言 本篇介绍的不是什么新知识,而是对前面讲解的一些知识的综合运用.众所周知,递归是解决复杂问题的一个很有效的方式,也是函数式语言的核心,在一些函数式语言中,是没有迭代与while这种概念的,因为此类 ...
- [Java 8] (8) Lambda表达式对递归的优化(上) - 使用尾递归 .
递归优化 很多算法都依赖于递归,典型的比如分治法(Divide-and-Conquer).但是普通的递归算法在处理规模较大的问题时,常常会出现StackOverflowError.处理这个问题,我们可 ...
- Java 递归、尾递归、非递归、栈 处理 三角数问题
import java.io.BufferedReader; import java.io.InputStreamReader; //1,3,6,10,15...n 三角数 /* * # 1 * ## ...
随机推荐
- C 2012年笔试题(保)
1 程序改错 1.1 下面程序段的功能是交换两个字符数组的内容(每个字符串字符数均不超过100) (8分) [ 见2012年笔试题1.1] void StrSwap(char *pa,char ...
- [codevs2370]小机房的树<LCA>
题目链接:http://codevs.cn/problem/2370/ 这题我还是做了比较久了,因为有人告诉我这是用tarjan离线做 好吧算我是蒟蒻,真心不懂tarjan怎么做,最后还是用倍增做的 ...
- 不可被忽视的操作系统( FreeRTOS )【2】
本文章总结基于官方FreeRTOS手册,测试系统为ESP32的IDF 4.0 本篇续上一篇<不可被忽视的操作系统( FreeRTOS )[1]> 其中上一篇主要内容为: FreeRTOS介 ...
- js 图片轮播简单版
<html> <head> <meta charset="utf-8" /> <title></title> <s ...
- 【Java技术系列】爱情36技之记忆永存
1. 关注“一猿小讲”的伙伴们都清楚,Java 那小子带着心爱的 Python 菇凉,去了一趟浪漫的土耳其,然后一起又去了东京和巴黎,接着 Python 菇凉自己又去了云南的大理. 就在昨天,Pyt ...
- markdown 插入图片太大?怎么设定图片大小?
你一定在插入图片的时候,遇到图片太大,影响观感的问题. Markdown中,图片大小的设定方式有两种 第一种: { this.a=a; this.b=b; } Mold ...
- Shell:Day05.笔记
交互输入与for语句 1.交互输入 read Python中用input()函数,进行输入: read命令同时可以定义多个变量值:而输入的内容默认以空格为分隔符,将值输入到对应的变量中: 如果默认 ...
- 分享layui的table的一些小技巧,前端分页
最近一直在折腾报表,期间使用了layui的table做展示(版本号:2.5.5) 起初:以为是查询结果出来后,前端和服务端分页一弄就完事了,参考例子,但是sql写得太长太长了,翻页困难,数据库是老旧的 ...