python3xiaobaike_2020/chapter5/5-3 python3小白课:递归函数.md
2025-04-20 23:22:14 +08:00

4.2 KiB
Raw Blame History

python3小白课递归函数

递归函数的定义

在一个函数的定义中,可以调用其他函数来完成一些操作。但如果在函数的定义内部调用函数自身(即自己调用自己),那么这个函数就称之为递归函数,递归函数是一种有趣的函数定义形式,在某些业务场景之下十分便利。比如文件层级遍历、目录树、一些数学算法等。

本节课我们就拿一个简单的数学算法来讲讲递归函数是如何定义的以及注意点。

引用百科的内容:

斐波那契数列Fibonacci sequence又称黄金分割数列、兔子数列是数学家列昂纳多·斐波那契于1202年提出的数列。

斐波那契数列为1、1、2、3、5、8、13、21、34……此数列从第3项开始每一项都等于前两项之和递推公式为F(n)=F(n-1)+F(n-2)n≥3F(1)=1F(2)=1。

在现代物理、准晶体结构、化学等领域斐波纳契数列都有直接的应用为此美国数学会从1963年起出版了以《斐波纳契数列季刊》为名的一份数学杂志用于专门刊载这方面的研究成果。

要完成斐波那契数列的递推生成,使用递归函数就是一个不错的选择。我们先来看一下代码:

# coding:utf-8
def fib(n):
    if n in [1, 2]:
        return 1
    else:
        return fib(n - 1) + fib(n - 2)
fib_seq = [fib(i) for i in range(1, 31)]
print(fib_seq)

如代码所示我们通过for表达式循环获取了一个斐波那契数列列表共30个元素传入是要求这个n要大于等于1这里就不写其他的判断语句了为了说明的简洁。

可以看到进入函数之后首先判断n是否为1或者2如果是的话则是固定的数1如果大于等于3的话就会返回调用自身函数的表达式只不过传入的参数变成了n -1或者n - 2。这样传入之后,就会各自调用自身来进行计算,当减少到一定程度之后,一定会到获取fib(1)、fib(2)的值而这两个值是固定的为1。所以整个函数调用得以结束。

[!danger]

编写递归函数时,当自身自调用到一定程度的时候,它能够获取确定的值,不再调用自身,如果不能,就会形成一种死循环,这是无意义的。

因此在写递归函数的时候,需要注意,递归一定要朝着已知的方向进行。


防止堆栈溢出

Note

这部分是比较偏底层原理的内容,如果不好理解,可以跳过。

使用递归函数需要注意防止栈溢出。在计算机中函数调用是通过栈stack这种数据结构实现的每当进入一个函数调用栈就会加一层栈帧每当函数返回栈就会减一层栈帧。由于栈的大小不是无限的所以递归调用的次数过多会导致栈溢出。

[!danger]

因此我们在使用递归函数的时候需要注意调用递归的层级不要太深太深容易导致栈溢出会报错在python中目前没有良好的机制来处理所以是存在这个问题的。

多深呢?比如上千层的递归调用。

还有一种情况是递归程度深,系统运算困难,速度慢。就拿刚才讲到的斐波那契数列来说,我们把代码改成这样:

这次我们一次次获取数列中的每个值打算跑1000次。

# coding:utf-8
def fib(n):
    if n in [1, 2]:
        return 1
    else:
        return fib(n - 1) + fib(n - 2)
for i in range(1, 1001):
    print("i: %s, fib(i): %s" % (i, fib(i)))

我们来运行看一下效果。

可以看到随着递归层级的加深,运算速度也在逐步减慢,有的时候甚至半天出不来一个结果了。

[!danger]

因此我们在实际运用中,注意递归层级不要过深。

单词释义

单词 释义
Fibonacci sequence 斐波那契数列fibseq为长单词短写本身不是单词
stack 栈,你可以理解为在一个容器中一块块放入木板,为加一层栈