白话算法-递归算法以及斐波那契数列递归优化算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/c_he_n/article/details/83053746

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毫无压力。从执行的结果来看,非递归>优化的递归>未优化后的递归。

参考

猜你喜欢

转载自blog.csdn.net/c_he_n/article/details/83053746