函数递归调用
函数的递归调用
在调用一个函数的过程中直接或间接地调用到了本身。函数的递归调用本质就是一个循环的过程(用函数实现的循环)。
递归调用必须在满足某种条件下结束,不能无限递归调用下去。
1、直接调用自身:
def f1():
print('from f1')
f1()
2、间接调用自身:
def f1():
print('from f1')
f2()
def f2():
print('from f2')
f1()
python不是一门函数式编程语言,无法对递归进行尾递归优化。尾递归优化,即在函数的最后一步(而非最后一行)调用自己。
在Python中,每调用一次函数就会在内存产生一个局部名称空间,所以为了防止递归死循环造成内存溢出,Python对递归的最大深度做了限制,默认为1000层。
# 查看最大深度。
import sys
print(sys.getrecursionlimit())
# 设置最大深度,但仍受限于操作系统栈大小的限制,不推荐修改。
sys.setrecursionlimit()
递归的两个阶段
例如要求出第一个人年龄,这个人比第二个人大10岁,第二个人又比第三个人大10岁,第三个人比第四个人大10岁,第四个人比第五个人大十岁,而第五个人的年龄为18岁,那么我们要求第一个人的年龄,就是:
man1 = man2 + 10
man2 = man3 + 10
man3 = man4 + 10
man4 = man5 + 10
man5 = 10
用代码来写就是这样:
def age(n):
if n == 1:
return 18
return age(n-1) + 10
执行过程:
回溯阶段
不断的向下一层函数递进,这个过程称为回溯。
print(age(5))
# age(5) -> age(4) -> age(3) -> age(2) -> age1(1)
递推阶段
满足结束条件,逐层返回值,这个过程称为递推。
age(5) <- age(4) <- age(3) <- age(2) <- age1(1)
58 <- 48 <- 38 <- 28 <- 18
递归应用
在写代码时,如果出现某个功能需要重复调用自身,这个时候就可以使用到递归。
二分法
对一个从小到大排序的有序数字元素列表,查找某个值在列表中的所在位置。若使用遍历查找,那么时间复杂度为O(n)。我们可以使用二分法查找,每次将值与列表中间的元素比较,若值比中间元素大,则下次从右边查找即可;若值比中间元素小,下次从左边查找即可。每次将值与列表的中间值比较,直到找到该值或无该值。
列表为:
l = [-4,-1,0,1,5,8,9,2,8,12,62,23,63]
Python实现二分法:
def dichotomy(n,num_list):
# 对列表排序。
num_list.sort()
if len(num_list) == 0:
# 表示列表为空,无该值.
return
median = len(num_list) // 2
if n > num_list[median]:
# 如果值大于中间值。
new_list = num_list[median+1:]
dichotomy(n,new_list)
elif n < num_list[median]:
# 如果值小于中间值。
new_list = num_list[:median]
dichotomy(n,new_list)
else:
# 不大不小表示找到该值。
print(f'{n} index is {median}')
阶乘
一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。
任何大于等于1 的自然数n 阶乘表示方法:
n! = n * n(n-1)!
Python代码实现:
def factorial(n):
if n == 1:
return n
return factorial(n-1) * n