递归算法的理解以及调优(尾递归)
提到递归首先想到的就是效率低下,但是为什么低下,看下下面的一段代码
public static void main(String[] args) { Integer result = recursion(5); System.out.println(result); } static Integer recursion(Integer n) { if (n < 1) { return 1; } else { return n * recursion((n - 1)); } } }
这段代码的执行过程:
开始
线性递归每次递归都会在内存中开辟新的空间存储结果等待结果: 5 * recursion((4)) 4 * recursion((3)) 3 * recursion((2)) 2 * recursion((1)) 得到结果逐层返回 2 6 24 120
resul=120
结束
下面给出优化版本的递归,也就是尾递归
public static void main(String[] args) { Integer result = recursion(1, 5); System.out.println(result); } static Integer recursion(Integer a, Integer n) { if (n == 0) { return a; } else { return recursion(a * n, n - 1); } } }
尾递归的执行过程:
开始 recursion(1*5,5) recursion(5*4,4) recursion(20*3,3) recursion(60*2,2) recursion(120*1,1)
result=120 结束
分析:
线性递归因为每次递归都要等待下面结果的返回,随着n的增加,时间复杂度和空间复杂度都是线性增长
尾递归中的n和a已经保存了递归的结果和深度,无需依赖下次递归的结果,每次递归系统无需开辟新的空间去记录中间值
好,接下来来一个进阶的题
题目:使用递归实现fibonacci(斐波那契数列),就是输入n,则算法fibonacci输出队列的第n项,fibonacci队列的定义是:1,1,2,3,5,8,13,21,34,55,89……,fibonacci的通项公式是f(n) = f(n-1) + f(n-2)
思考一下实现形式……
- 初级实现方式:
public static void main(String[] args) { int result = recursion(10); System.out.println(result); } static Integer recursion(Integer n) { if (n < 2) { return 1; } else { return recursion(n - 1) + recursion(n - 2); } } }
分析:以上就是使用了两个线性递归进行通项公式的实现
- 中级的实现方式:
思考:有大于一个的线性递归,使用空间换时间,在线程进行第一次递归的时候是不是能将递归的结果保存下来,当第二次线性递归的时候直接从变量里面去取,以下是代码实现
package com.zzq.controller; import java.text.ParseException; /** * @author zhangzhaoqiang */ public class Application { final int MAX_N = 2048; private int[] _cacheInt = new int[MAX_N]; public static void main(String[] args) { Application application = new Application(); int result = application.recursion(10); System.out.println(result); } Integer recursion(Integer n) { if ( _cacheInt[n] != 0 ) { return _cacheInt[n]; } if (n <= 1) { _cacheInt[n] = 1; return 1; } else { _cacheInt[n] = recursion(n-1)+recursion(n-2); return _cacheInt[n]; } } }
分析:因为两个递归调用都是在一个线程中完成,所以在第一次递归的时候将递归的中间结果保存下来,这样在进行第二次递归的时候就能直接从_cacheInt取到
- 高级实现方式
思考:采用尾部递归的实现方式来实现,上代码
public class Application { public static void main(String[] args) { Application application = new Application(); int result = application.recursion(10); System.out.println(result); } int recursion(int n) { return recursion(1, 0, n); } int recursion(int a, int b, int n) { if (n == 0) { return a; } else { return recursion(a + b, a, n - 1); } } }
分析:上面就采用尾递归的实现方式进行实现
以上是我能想到的三种实现方式,如果有更好的实现方式欢迎留言交流。