欢迎访问宙启技术站
智能推送

实现递归算法计算斐波那契数列

发布时间:2023-06-25 10:11:51

斐波那契数列,是一种非常著名的数列,其起始值为0和1,之后的每一个数都是前面两个数之和。换句话说,第n个斐波那契数f(n)可以通过以下递归公式计算:

f(n) = f(n-1) + f(n-2)

斐波那契数列的前几个数为0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144……以此类推。

在递归过程中,我们会发现计算机需要不断地进行函数调用,而这种调用方式会导致计算机的调用栈不断地增加,从而占用越来越多的内存空间,这很容易导致计算机崩溃。因此,斐波那契数列问题不能仅仅用递归算法来解决,我们需要寻找更好的解决方式。

非常重要的一点是,递归算法存在大量重复计算,导致效率较低,效率提升方法有记忆化搜索和动态规划等。

下面,我们就针对斐波那契数列问题来探讨递归算法的实现:

1. 编写递归函数

首先,我们可以从编写递归函数开始来实现斐波那契数列问题。这种方式可以很好地理解递归算法在计算这个问题时的每一步操作,并进一步帮助我们深入学习递归算法。

具体来说,在编写递归函数时,我们可以将任务划分为两个部分: 部分是在递归到第N位之前,我们需要先计算出第n-1位和第n-2位;第二部分是在第N位时,我们将第n-1位和第n-2位相加,得到第N位的值。

具体的代码实现如下所示:

def Fib(n):
    if n < 0:
        print("输入错误!")
    elif n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return Fib(n-1) + Fib(n-2)

这段代码中,我们对输入进行了简单判断,如果输入是负数,我们会输出错误信息,并返回0;否则,当n等于0时,返回0;当n等于1时,返回1。在进行递归计算时,函数中需要调用自身。

在这个函数中,我们首先进行了输入的判定,如果发现输入不合法,那么我们就会输出错误信息并返回0;否则,当输入为0和1时,直接返回f(0)=0和f(1)=1的值。

在递归计算时,需要执行f(n-1)和f(n-2)的计算,然后将结果求和,作为第n位的值。需要注意的是,在递归计算时,我们需要对每个计算结果进行缓存,以便于后续计算时可以直接调用,避免重复计算。

2. 斐波那契数列的特性与缺点

斐波那契数列具有以下特性:

1) 纯递归,实现简单容易理解,但效率差,非常占用计算机内存,容易引起栈溢出的问题;

2) 可以用循环来实现,这种方式比递归要更加高效一些。循环代码如下所示:

def loop_Fib(n):
    if n < 0:
        print("输入错误!")
    elif n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        a = 0
        b = 1
        for i in range(1, n):
            sum = a + b
            a = b
            b = sum
        return b

在这个代码中,我们首先对输入进行了相同的测试,以避免负数输入和非整数输入造成的错误。接下来,我们使用了a和b两个变量来存储斐波那契数列的前两个数,然后用循环迭代计算从第三个数开始,直到第n个数为止。在迭代时,我们计算出a和b的和,并将结果赋值给b,再将原来的b赋值给a。最后,我们返回b的值。

3. 记忆化搜索/动态规划

可以看出循环算法具有非常高的效率,并且不会受到计算机栈的限制,但仍然存在执行时间和空间问题。

为了进一步提高斐波那契数列的计算效率,我们可以使用记忆化搜索或动态规划技术。

记忆化搜索,也叫备忘录法,是一种用来优化递归算法的技术,它通过自上而下的递归计算,但是在计算的过程中,我们将中间结果缓存到等待查找时可以直接调用。这种方式可以避免反复计算,大大提高了斐波那契数列的计算效率。同时,由于每次计算时都是从缓存中取值,因此内存占用也不会过大。下面是代码实现:

def Fib_mem(n, memo = {}):
    if n < 0:
        print("输入错误!")
    elif n in memo:
        return memo[n]
    elif n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        memo[n] = Fib_mem(n-1, memo) + Fib_mem(n-2, memo)
        return memo[n]

在这段代码中,我们增加了一个memo参数用来存储中间结果。在进行递归计算时,我们首先从缓存中查找是否已经计算过,如果已经计算过,直接返回结果。如果没有计算过,我们就从第n-1和n-2位开始计算,并将结果缓存到memo中。最后,我们返回中间结果。使用了这种方法之后,我们将大幅提升计算效率。

而动态规划则更加注重的是自下而上的计算,即我们从Fib(0)和Fib(1)开始,逐步计算之后的数值。这种方式将迭代计算重复的子问题,并且会按照一定的顺序进行计算。具体来说,我们可以使用一个数组或者哈希表来保存之前计算过的结果,并在迭代计算过程中,不断使用已经计算的结果来计算新的结果,直到计算得到第n位数值为止。下面是代码实现:

def Fib_dynamic(n):
    if n < 0:
        print("输入错误!")
    elif n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        fib_arr = [0, 1]
        for i in range(2, n+1):
            fib_arr.append(fib_arr[i-1] + fib_arr[i-2])
        return fib_arr[n]

在这段代码中,我们首先对输入进行相同的测试,如上所述。然后,创建一个数组来存储斐波那契数列的前两个数0和1,然后使用循环计算从第三个数开始