1.什么是递归?
先来看一用了递归的例子:
int f(int n) {
if (n == 1)
return 1;
return f(n-1) + n;
}
这个函数实现了从1到n的求和,看上去是不是很简单啊,理解上可能会有困难,但是你知道,什么样的问题可以采用递归算法解决呢?
1.一个问题能不能分解成子问题
2.分解的子问题,除了问题规模会变小之外,和父问题解决的思路是一样的,
3.有没有一个终止条件存在。
递归算法的关键在于如何将一个问题分解成子问题。
举个例子:
用上面的求和来看看如何写出递归的代码的。
f(n) = 1+2+3+4+5+6+7+8+9+…+n
例:f(9) = 1+2+3+4+5+6+7+8+9;
解题思路:
把上面的问题给分解成子问题,若想求出f(9)的值,你必须求出f(8)因为f(9)=f(8)+9
以此类推:
f(9)=f(8)+9
f(8)=f(7)+8
f(7)=f(6)+7
f(6)=f(5)+6
f(5)=f(4)+5
f(4)=f(3)+4
f(3)=f(2)+3
f(2)=f(1)+2
f(1)=1
从中是不是发现这么一个规律:f(n)=f(n-1)+n,它的结束条件就是 f(1)= 1,这个求和的问题就是典型的递归算法,它可以分解成子问题,除了规模变小之外,子问题和父问题解决思路还是一样的,有个结束条件,这是满足递归的三个条件的。
斐波那契数列的实现以优化
可以根据递归调用的栈画出递归调用的树,如下图:
从上图可以看出,许多地方是重复计算的,也就是说,我们是不是可以从这方面去着手考虑优化问题,可以将计算过的存起来,在递归计算时,首先判断是否计算过,若计算过就直接取就行了,这样大大提高计算的速度和防止栈的溢出。优化代码如下:
public class Tests {
static Map<Integer, Integer> temp = new HashMap<>();//存放计算的中间值,避免重复计算
public static void main(String args[]) {
long stat = System.nanoTime();
int a1 = FibonacciOptimize(30);
long end = System.nanoTime();
System.out.println("优化过的递归:结果为" + a1 + " 耗时为:" + (end - stat));
long stat1 = System.nanoTime();
int a2 = Fibonacci(30);
long end1 = System.nanoTime();
System.out.println("未优化的递归:结果为" + a2 + " 耗时为:" + (end1 - stat1));
long stat2 = System.nanoTime();
int a3 = FibonacciNorecurrsive(30);
long end2 = System.nanoTime();
System.out.println("非递归的算法:结果为" + a3 + " 耗时为:" + (end2 - stat2));
}
static int f(int n) {
if (n == 1) {
return 1;
} else {
return f(n - 1) + n;
}
}
/*
未优化过的斐波那契
*/
static int Fibonacci(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
/*
未优化过的斐波那契
*/
static int FibonacciOptimize(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
if (temp.containsKey(n)) {//判断是否计算过
return temp.get(n);
}
int ret = FibonacciOptimize(n - 1) + FibonacciOptimize(n - 2);
temp.put(n, ret);//把计算过的放在temp中,若遇到计算过的就直接取
return ret;
}
/*
非递归的斐波那契
*/
static int FibonacciNorecurrsive(int n) {
if (n == 0) return 0;
else if (n == 1) return 1;
int a = 0, b = 1, c = 0;
for (int i = 1; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return c;
}
}
结果:
优化过的递归:结果为1346269 耗时为:136533
未优化的递归:结果为1346269 耗时为:5443690
非递归的算法:结果为1346269 耗时为:10240
未经过优化的斐波那契数列递归算法,计算40的时候已经很慢,50更不用说了,但是优化后的50毫无压力。从执行的结果来看,非递归>优化的递归>未优化后的递归。