课时30:方法递归调用
方法的递归调用指的是一个方法自己调用自己的情况,利用递归调用可以解决一些重复且麻烦的问题。比如在处理数据结构时,最初常常会涉及一些复杂的算法和各种游戏逻辑。在进行方法递归调用的时候一般需要
考虑如下几点问题:
1. 一定要设置方法递归调用的结束条件(比如说“猫捉老鼠”,假设我们在猫的尾巴后面绑一只小老鼠,这只猫就会不停地转圈。在这个过程中,你只需要告诉大家一声“抓老鼠”,它就会开始转圈。);
2. 每一次调用的过程中一定要修改传递的参数条件。
范例:实现一个1~100的累加
public class JavaDemo { public static void main(string args[]) { int sum=0; int x =1; while(x<=100){//循环的结束条件 sum+=x; x++;//修改每一次循环的变量 } System.out.println(sum); } }
计算结果:5050
也可通过递归的形式实现:
public class JavaDemo { public static void main(string args[]) { System.out.println(sum(100)); } public static int sum(int num){//执行累加 return num+sum(num-1);//递归调用 } }
陷入死循环,应设置限制条件,修改后:
public class JavaDemo { public static void main(string args[]) { System.out.println(sum(100)); } public static int sum(int num){//执行累加 if(num==1){//不累加了 return1; } return num+sum()num-1;//递归调用 } }
计算结果:5050
下面对此代码进行一些简单的分析处理:
【第1次执行sum()、主方法执行】return100+sum(99)
;
【第2次执行sum()、sum()递归调用】return99+sum(98)
;
………………
【第99次执行sum()、sum()递归调用】return2+sum(1)
;
【第100次执行sum()、sum()递归调用】return1
;
整体形式: return 100+99+98+……+2+1;递归操作虽然可以简化的调用。但是在实际的开发之中,你们所编写的代码可能很少会出现有递归情况。大部分情况下考虑的都只是一些简单的处理逻辑。递归少去使用还有另外一个原因:如果处理不当,则会造成内存溢出。
范例:计算“1!+2!+3!+4!+5!+……+90!
”
有一个有趣的小故事,虽然与阶乘关系不大,但它涉及一个倍增的概念。曾经有一个国家陷入困境,而国王却非常吝啬。有一个人生病了,他找到国王说:“我能治好你的病,但你必须满足我的要求:在围棋棋盘的每个小格上,第一个小格放一粒米,第二个小格放两粒米,依次类推。”国王站在那里,表示非常满意。于是,国王要求他去治病。最后,当棋盘上的米粒全部放完时,国王才发现自己已经给了他半个国家的粮食,而他用这些粮食去治病了。
阶乘的过程实际上也是一个倍增的过程。那么,什么是阶乘呢?很简单:1的阶乘是1,2的阶乘是1乘以2(等于2),3的阶乘是6。
上图是90的阶乘,已经非常庞大了。如果出现这样的结果,我们应该知道,只有double类型才能存储这样的数据。如果我们真的考虑阶乘计算,那么就必须确定合适的数据类型。
在进行阶乘计算的时候必须要考虑选择的数据类型,肯定不能够使用int或long,只能够使用double。而且如果阶乘的数值更大,double类型也装不下,我们就需要采用其他方式来处理。
public class JavaDemo { public static void main(string args[]) { System.out.println(fan(90)); } public static double fan(int num){//执行累加 if(num==1){//不累加了 return1; } return num*fan()num-1;//递归调用 } }
计算结果:1.4857159644817607E138
若要累加结果
public class JavaDemo { public static void main(string args[]) { System.out.println(sum(90)); } public static double sum(int num){ if(num==1){ return1; } return fan(num)+sum(num-1) } public static double fan(int num){//执行累加 if(num==1){//不累加了 return1; } return num*fan()num-1;//递归调用 } }
计算结果:1.502411524554385E138
实际上有一部分的递归都是可以通过循环来完成,但是如果使用递归要比使用循环结构看起来更加清晰一些。除非必要,否则我不建议大家把所有精力都放在递归调用上。了解递归的基本形式就足够了。因为如果你上过大学并接受过专业训练,就能很容易理解这个过程。但如果这个过程不清楚,也不要纠结,意义不大。我们只有在分析原理时才会用到它,只要原理清楚即可。