关于递归的一些个人理解
熟练的运用递归往往能写出非常简洁的代码,但是正是由于代码太过简洁,就会导致递归可能有点难于理解,每次在学习递归的时候,都是似懂非懂的样子,一旦想的很深入,就很容易把自己陷进去,刚理解的就好像又乱了。
这几天总结了一个有关递归的心得,写下来希望分享一下,也希望得到大神的指点。
1.什么问题可以用递归解决
首先解题时如果遇到大问题可以拆解同样的更小的问题的情况,大部分都可以用递归来解决。比如最典型的阶层,斐波那契数列,二叉树的遍历,汉诺塔等。
2.怎么去写这个递归函数recursion()
首先,我们必须明确一点,写这个递归函数是干什么的,也就是这个函数的功能,这一定要明确,然后我们需要找到这个递归函数的出口。
我们从最简单的递归说起,就比如阶层的计算中fun(n)这个用来递归的函数是为了计算n的阶层的,这点首先要明确。
int result = 0;
pubic int fun(n){
if (n == 1){
return 1;
}
return n*fun(n-1);
}
不妨我们取n=5;计算的5的阶层即为54321,其实它可以变成54!又可以变成543!,这里变得每一步都是一个更小的阶层,什么时候我们不需要计算阶层直接得到结果呢,显然是1的时候,这就是递归函数的出口。
那么进入递归函数的内部,你传入一个5是为了计算5的阶层,为了计算5的阶层,那你必须先知道4的阶层,即54!,那什么函数可以计算4的阶层呢,就是fun(4),所以直接5*fun(4)就可以了。你不需要再往深处想,这样就够了。
可能听了上面这个还是似懂非懂,那就再说一个经典的问题,汉诺塔问题,不太清楚的先去百度一下汉诺塔的情况。
汉诺塔问题递归函数的出口其实就是当只有一个盘的时候,直接移动就好,不需要其他操作,这里我定义了一个递归函数hanoiTower(num,x,y,z)表示**将num个盘子从x移到z,y作为一个辅助的。**这句话就是这个递归函数功能,认准他就好了
public class Hanoitower {
static int count = 0;
public static void main(String[] args) {
hanoiTower(20,'x','y','z');
System.out.println(count);
}
/**
* num代表还有几个盘
* x为原盘
* y为辅助盘
* z为目标盘
*/
public static void hanoiTower(int num,char x,char y,char z){
count++;
if (num ==1){
System.out.println("第1个盘从"+x+"------>"+z);
}
else{
//1.当num>=2,都可以看成两个盘,最下面的盘和他上面的所有盘,我们总是
//将上面的所有盘先移到辅助盘上
hanoiTower(num-1,x,z,y);
System.out.println("第"+num+"个盘从"+x+"------>"+z);
hanoiTower(num-1,y,x,z);
}
}
}
出口找到了,那我们进入递归函数的内部,要想把num个盘从x移动到z,我们是不是要借助y,也就是我们要把num-1个盘先从x移动到y,才能直接把最大的盘移到z,这个功能是不是就是num-1个盘x到y,z做辅助,不就是hanoiTower(num-1,x,z,y)嘛,这时候,我们就可以把最底下的盘子放到z了,所以就输出System.out.println("第"+num+"个盘从"+x+"------>"+z);
,而这时候,有需要把移动到y上的sum-1个盘子移到z,这时候x做辅助,hanioTower(sum-1,y,x,z)是不是就可以实现,那么整个递归函数也就写完了。
3.总结
关注递归函数的功能,找到递归函数出口,从整体看问题,不要把自己往递归里绕。