递归函数介绍
函数不仅可以嵌套定义,还可以嵌套调用,即在调用一个函数的过程中,函数内部又调用另一个函数,而函数的递归调用指的是在调用一个函数的过程中又直接或间接地调用该函数本身
#直接调用本身
def f1():
print('from f1')
f1()
f1()
#间接调用本身
def f1():
print('from f1')
f2()
def f2():
print('from f2')
f1()
f1()
调用函数会产生局部的名称空间,占用内存,因为上述这种调用会无需调用本身,python解释器的内存管理机制为了防止其无限制占用内存,对函数的递归调用做了最大的层级限制
# 修改最大递归深度
import sys # 操作软件模块
print(sys.getrecursionlimit()) # 查询递归深度,不精准 998个左右
sys.getrecursionlimit(2000) # 修改递归深度
回溯与递推
回溯 : 就是一次次重复的过程,这个重复过程必须建立在复杂程度递减的情况下,直到有一个最终的结束条件
递推 : 一次次往回推导的过程
递归函数不需要考虑循环次数,但必须要有结束条件
def age(n):
if n == 1:
return 10 # 结束递归回溯的条件
return age(n-1) + 2 # 递推
res = age(5)
print(res)
python中的递归效率低且没有尾递归优化
python中的递归效率低,需要在进入下一次递归时保留当前的状态,在其他语言中可以有解决方法:尾递归优化,即在函数的最后一步(而非最后一行)调用自己,
但是python又没有尾递归,且对递归层级做了限制
总结递归的使用:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)