zoukankan      html  css  js  c++  java
  • 递归与斐波那契数列

    递归是程序设计中经常遇到的概念,一些数学问题经常能用递归的方式解决,并且在算法设计中也能用到递归。笔者在最近学习算法的过程中,遇到了一种可以用递归方式实现的算法——归并排序,在介绍这个算法之前,有必要先把递归的概念介绍一下。所以本篇主要介绍递归的概念,并通过它的一个应用——斐波那契数列来说明。

            递归简单来说就是如果一个函数或方法在执行时,直接或间接地调用了自己,那么这个过程就是递归的,这个方法就是递归的方法。它通常会把一个大型的复杂的问题一层一层地转化为一个一个与原问题相似的规模较小的问题,并逐层解决这些较小的问题,最后将整个大的问题解决。

            递归的实现必须满足一定条件,首先原问题与子问题的处理方式应该一样,这样递归产生的各个子问题就可以用相同的方式解决;其次,递归不能无限递归,必须有一个结束的条件,当满足这个条件时,停止递归,返回去逐层解决各个子问题。

            通常基于递归方式编写的代码会比基于循环方式实现的代码简洁许多,也更加容易实现。但它的缺点也是很明显的,递归是函数或方法不断调用自身的过程,在这个不断调用的过程中是需要消耗时间和空间的,每一次的调用都需要在内存栈中分配空间来保存参数、返回地址和临时变量,同时数据的入栈和出栈都需要时间,这就导致有些时候递归的实现效率并不如循环。同时,递归就是把一个大的问题不断分解成各个子问题的过程,这些子问题可能会存在重复的现象,而这些重复就会给程序的性能带来负面影响,从而影响执行效率。除此以外,递归还可能引发更严重的问题:栈溢出。前面提到函数或方法的每一次调用都需要在内存栈中分配空间,而每个进程的栈的容量是有限的,当递归调用的层级过多时,可能会超出栈的容量,从而导致调用栈溢出。

            虽然递归有一些缺点,但递归简化了程序设计,使程序更容易阅读和理解,并且随着科技的不断发展,计算机的运算性能越来越高,所以能用递归方式解决的问题可以优先考虑递归。下面介绍一个用递归方式解决的经典问题——斐波那契数列。

            斐波那契数列指的是这样的一组序列:第1项是0,第2项是1,从第3项开始,每一项的值都等于前两项之和(即f(n)=f(n-1)+f(n-2))。

            斐波那契数列的数学表示:

            计算斐波那契数列的第n项,假设n=20。

            递归代码:

    复制代码
    //递归方式
        public static int fibonacci1(int n) {
            if(n == 0)      return 0;
            else if(n == 1) return 1;
            else            return fibonacci1(n-1) + fibonacci1(n-2);
        }
    复制代码

            可以看到递归方式实现斐波那契数列的代码非常简洁,但仔细研究会发现,求f(20)得先求出f(19)和f(18),求f(19)得先求出f(18)和f(17),求f(18)得先求出f(17)和f(16)……以此类推可以发现,里面有重复的求值操作,比如f(18)、f(17)等都计算了两次。当数据量很大时,重复的求值操作会非常多,就像前面所说,这就影响了程序的执行效率。当然,我们也可以使用非递归的方式。

            非递归代码:

    复制代码
    //非递归方式
        public static int fibonacci2(int n) {
            if(n == 0)      return 0;
            else if(n == 1) return 1;
            int a = 0, b=1, c = 0;
            for (int i = 2; i <= n; i++) {
                c = a+b;
                a = b;
                b = c;
            }
            return c;
        }
    复制代码

            这样就解决了重复计算的问题,但本文主要研究的是用递归方式。

            完整代码:以Java为例。

    复制代码
    /*
     * 斐波那契数列
     */
    public class Fibonacci {
        //递归方式
        public static int fibonacci1(int n) {
            if(n == 0)      return 0;
            else if(n == 1) return 1;
            else            return fibonacci1(n-1) + fibonacci1(n-2);
        }
        //非递归方式
        public static int fibonacci2(int n) {
            if(n == 0)      return 0;
            else if(n == 1) return 1;
            int a = 0, b=1, c = 0;
            for (int i = 2; i <= n; i++) {
                c = a+b;
                a = b;
                b = c;
            }
            return c;
        }
        public static void main(String[] args) {
            System.out.println("斐波那契数列第20项为:"+fibonacci1(20));
            System.out.println("斐波那契数列第20项为:"+fibonacci2(20));
        }
    }
    复制代码

            运行结果:

    斐波那契数列第20项为:6765
    斐波那契数列第20项为:6765
    zhuanzi http://www.cnblogs.com/Y-oung/p/7835180.html
  • 相关阅读:
    .NET5微服务示例-Ocelot网关
    .NET5微服务示例-Polly熔断与降级
    .NET5微服务示例-Consul注册中心
    .NET下使用ELK日志中心
    [ 题解 ] [ 数学 ] [ JZOJ5809 ] 数羊
    [ 题解 ] [ 数学 ] 函数 (sequence) (欧拉函数)
    [ 题解 ] [ JZOJ5777 ] 小 x 玩游戏
    更换谷歌浏览器视频输入源
    axios 封装及 API 接口管理
    小程序代码压缩实践
  • 原文地址:https://www.cnblogs.com/shizhijie/p/8428796.html
Copyright © 2011-2022 走看看