递归函数的定义:递归函数即自调用函数,在函数体内直接或间接的调用自己,即函数的嵌套是函数本身。
打个生动的比喻:我们可以把” 递归 “比喻成 “查字典 “,当你查一个词,发现这个词的解释中某个词仍然不懂,于是你开始查这第二个词。可惜,第二个词里仍然有不懂的词,于是查第三个词,这样查下去,直到有一个词的解释是你完全能看懂的,那么递归走到了尽头,然后你开始后退,逐个明白之前查过的每一个词,最终,你明白了最开始那个词的意思。(摘自知乎的一个回答)
下面是计算整数i的阶乘的递归方法。
/*
求整数i的阶乘
*/
public static int fac(int i) {
if(i==1) {
return 1;
}
else
return i*fac(i-1);
}
斐波拉契数列:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)
public static int fib(int num) {
if(num == 1 || num == 2) {
return 1;
}else {
return fib(num - 2) + fib(num - 1);
}
}
经典案例:汉诺塔算法
/*
* 某寺庙前有三根柱子A、B、C,开始时A柱上有n个盘子,盘子大小不等,大的在下、小的在上,
* 有一老和尚想把这n个盘子从A柱移到C柱上,但每次只允许移动一个盘子(如上图所示),
* 且在移动过程序中每根柱子上都始终保持大盘在下、小盘在上。在移动过程中可以借助B柱。
* 要求:正整数n由键盘输入。
*/
public class Hanoi {
public static void main(String[] args) {
Scanner s=new Scanner(system.in );
System.out.println("请输入n:");
int input=s.nextInt();
hanoi(input,'A','B','C');
}
public static void move(char A,int n,char C) {
System.out.println("将编号为"+n+"的盘子从"+A+"转移到"+C);
}
public static void hanoi(int n,char A,char B,char C) {
if(n==1) {
move(A,1,C);//如果只有一个盘,则直接将该盘从A转至C
}
else {
hanoi(n-1,A,C,B);//将编号为n-1的盘子从A通过C转至B
move(A,n,C);//将A最底层盘转至C
hanoi(n-1,B,A,C);//将标号为n-1的盘子从B通过A转至C
}
}
}
总结:
优点:相比非递归函数,递归函数代码更简洁清晰,可读性更好。
缺点:由于调用递归函数需要多次用到系统栈内存,所以空间消耗要比非递归代码要大很多。而且,如果递归深度太大,或者由于函数本身逻辑错误可能会导致内存溢出,系统崩溃。