@[ToC]
递归
- 递归就是一个函数直接或间接的调用自己.一般来说,递归需要有边界条件,递归前进段和递归返回段.当边界条件不满足的时,递归前进,当边界条件满足的时候,递归返回.
递归就是在过程或者函数里调用自身.
在使用递归策略时.必须有一个明确的递归结束条件,称为递归出口. - 递归一般用来解决三类问题:
- 数据的定义是按照递归定义的(Fibonacci函数,n的阶乘)
- 问题解法按递归实现(回溯)
- 数据的结构形式是按照递归定义的.(二叉树的遍历,图的搜索)
递归的缺点:
递归解题相对常用的算法如普通循环等,运行效率较低(所有的循环问题都可以用递归来解决).<font color ="red">在递归调用的过程当中系统为每一层的返回点,局部变量等开辟了栈来存储,因此递归次数过多容易造成栈溢出.</font>
使用线性递归来实现斐波那契
public int fa(int n){
if(n<2)
return n;
return fa(n-1)+fn(n-2);
}
上面函数的执行过程.中间可以看出每一个函数都存在重复调用的情况.这个时候可以使用打表的方法来消除重复计算
public int fa(int n, Map<Integer ,Integer> map){
if(n==0 || n==1)
return n;
if(map.containsKey(n)){
return map.get(n);
}
Integer put = map.put(n, fa(n - 1, map)+ fa(n-2,map));
return n*put;
}
测试也可以发现使用map后函数的执行时间减少了很多
尾递归
-<font color="red ">尾递归就是把当前的运算结果放在参数传给下层函数,使用尾递归可以减少堆栈的占用量.</font>
如上面的代码可以写成
public static int fa2(int n,int ret1,int ret2){
if(n==0)
return ret1;
return fa2(n-1,ret2,ret1+ret2);
}
如果n=5 ,ret1=0 ,ret2=1;
从图中可以看出,尾递归不需要向上返回了,但是需要引入两个参数来保持运算结果.