java中,一个方法调用它自身,被称为方法递归。方法递归中包含了一种隐藏式的循环。它会重复执行某段代码,而且不需要循环语句控制。
例如有如下数学题。已知一个数列:f(0) =1 、f(1)=4、f(n+2) =2*f(n+1) + f(n),其中n是大于0的整数,求f(10)的值。这题中函数中
带有函数的计算,for循环不好写代码,就可以使用递归方法来求。程序如下
上面方法fn体中,再次调用fn的方法,这就是方法的递归。
对于fn(10),即等于2*fn(9)+fn(8),其中fn(9)=2*fn(8)+fn(7),其中f(8)=2*fn(7)+f(6)······依次往里面推导,最终会
计算到fn(2)等于2*fn(1)+f(0),而式中n=0和n=1就是递归的出口,这个式子可以算出来的,然后按计算的顺序一步一步的返回,
最终会得到fn(10)的值。
对上面递归例子,当一个方法不断的调用自身的时候,必须要在某个时候的返回值是确认的,而不是还在调用自身,否则递归成了死循环,
,没有出口的循环。固设计递归的方法时,一定要设计好出口,像上式中if(n==0)返回的是个确认值。
在举几个经典事例:
A:斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
如果设F(n)为该数列的第n项(n∈N*),求出第项的数:
F(n)=F(n-1)+F(n-2);(n>2)
方法的流程如下:
返回的顺序是按调用方法的次序,并依次返回的。
B:求数的阶乘。
C:求x的n次方(也可以调用math类的paw方法)
D:汉诺塔算法:
古代有一个梵塔,塔内有三个座A、B、C,A座上有64个盘子,盘子大小不等,大的在下,小的在上。婆罗门的门徒想把这64个盘子从A座移到C座,但每次只能允许移动一个盘子,并且在移动过程中,3个座上的盘子始终保持大盘在下,小盘在上。在移动过程中可以利用B座。
汉诺塔中递归方法总体思想:
1. 先将A上面的n-1个盘子,移到B柱上
2. 然后把A上最大的一个盘子放到C上去(C相当于空)
3. 然后把B上面的n-1个盘子移到A上去
4.在吧B上的最大的盘中移动到C上去(C相当于空)。
以3阶的汉诺塔为例子,执行上述方法
总:执行move(3,A,B,C)--
判断条件3==1?---执行else
执行move(3-1,A,C,B)---(将b,c柱子调换)--调用自身
判断2==1?--执行else
执行move(2-1,A,B,C)--(将b,c柱子调换)--调用自身
判断1==1?--执行if
输出:从 A 移动盘中子 1 号到 C中, 【1】
level==1为递归出口,故返回到上一级;
继续执行方法体中的语句--此时move中level是为2的,
System.out.println(从 A 移动盘子 2 号到 B) 【2】
执行move(2-1,2,1 ,,3 )--拿move(2,A,C,B)为 (1,C,A ,B)
判断1==1?--执行if
输出:从 C 移动盘子 1 号 到B; 【3】
返回到上一级
第一个递归方法调用完了,返回主方法体,继续执行,此时level是为3的
Systrm.out.println(从 A 移动盘子 3号 到 C)--这里的柱子还是(3,A,B,C) 【4】
执行move(3-1,2,1,3)--拿move(3,A,B ,C)为move(2,B,A,C)
判断2==1?--执行else
执行move(2-1,1,3,2)-拿move(2,B,A,C)为move(1,B,C,A)
判断1==1?if
输出:从 B 移动盘中 1号到 A 【5】
level==1为递归出口,故返回上一级
执行方法体中的输出,此时level为2,move(2,B ,A ,C)
System.out.println(从 B 移动盘子 2号 到 C) 【6】
move(2-1,2 , 1 , 3)--拿move(2,B,A,C)为move(1,A,B,C)
判断1==1?执行if
输出:从A 移动盘中1号 到C 【7】
返回到上一级
返回上一级;
方法全部执行完毕,结束方法。
要注意柱子的切换,每次执行方法都会变换。回到上一级就用同级的柱子顺序。
总结:递归算法来说,这个根就是那个出口,只要找到这个出口所在,那么算法自然而然就能水到渠成了。
可以先写出前面几种情况,推导出公式和递归出口。