文章目录
这里是一段防爬虫文本,请读者忽略。
本文原创首发于CSDN,作者IDYS
博客首页:https://blog.csdn.net/weixin_41633902/
本文链接:https://blog.csdn.net/weixin_41633902/article/details/107775824
未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!
写在开头的话
- 请记住:实践是掌握知识的最快方法
- 如果你只是怀着看看的态度去快速浏览文章,而不去认认真真的把文章里面讲的任何一个知识点去实践一遍,那么你永远也掌握不了它
- 生命不息,折腾不止!
Python 递归函数
00. 递归
- 函数直接或者间接调用自身就是递归
- 递归需要有边界条件、递归前进段、递归返回段
- 递归一定要有边界条件
- 当边界条件不满足的时候,递归前进
- 当边界条件满足的时候,递归返回
-
递归要求
- 递归一定要有退出条件,递归调用一定要执行到这个退出条件。没有退出条件的递归调用,就是无限调用
-
递归调用的深度不宜过深
Python
对递归调用的深度做了限制,以保护解释器- 超过递归深度限制,抛出
RecursionError: maximum recursion depth exceeded in comparison
异常 sys.getrecursionlimit()
:查看系统调用深度
01. 演示:用递归调用求斐波那契数列
- 代码演示
import sys
def fn(n):
if n == 1 or n == 2: # 边界条件
return 1 # 返回段
else:
return fn(n-1) + fn(n-2) # 前进段
if __name__ == "__main__":
num = fn(30)
print(num)
print(sys.getrecursionlimit()) # 查看递归调用最大深度
- 运行结果
832040
1000
02. 递归调用的性能
- 循环稍微复杂一些,但是只要不是死循环,可以多次迭代直至算出结果
fib
函数代码极简易懂,但是只能获取到最外层的函数调用,内部递归结果都是中间结果,而且给定一个n
都要进行2n
次递归,深度越深,效率越低。为了获取斐波那契数列,需要外面再套一个n
次循环,效率就更低了- 递归还有深度限制,如果递归复杂,函数反复压栈,栈内存很快就溢出了
- 递归调用性能:代码演示
import datetime
def fn(n):
if n == 1 or n == 2: # 边界条件
return 1 # 返回段
else:
return fn(n-1) + fn(n-2) # 前进段
if __name__ == "__main__":
start = datetime.datetime.now()
print(fn(30))
print((datetime.datetime.now() - start).total_seconds())
- 运行结果
832040
0.353054
- 普通的循环函数:求斐波那契数列演示
import datetime
def fn(n):
i, j = 1, 1
for k in range(n-2):
i, j = i+j, i
return i
if __name__ == "__main__":
start = datetime.datetime.now()
print(fn(30))
print((datetime.datetime.now() - start).total_seconds())
- 运行结果
832040
0.0
发现递归调用花费的时间远远大于普通函数所花费的时间
- 改进版斐波那契数列递归调用
- 代码演示
import datetime
def fn(n,i,j):
if n == 2:
return i
else:
i, j = i+j, i
return fn(n-1, i, j)
if __name__ == "__main__":
start = datetime.datetime.now()
print(fn(999, 1, 1))
print((datetime.datetime.now() - start).total_seconds())
- 运行结果
26863810024485359386146727202142923967616609318986952340123175997617981700247881689338369654483356564191827856161443356312976673642210350324634850410377680367334151172899169723197082763985615764450078474174626
0.002992
这次发现就算其递归调用999次,其运行时间也仅仅只有0.002992秒
03. 递归总结
- 递归是一种很自然的表达,符合逻辑思维
- 递归相对运行效率低,每一次调用函数都要开辟栈帧
- 递归有深度限制,如果递归层次太深,函数反复压栈,栈内存很快就溢出了
- 如果是有限次数的递归,可以使用递归调用,或者使用循环代替,循环代码稍微复杂一些,但是只要不是死循环,可以多次迭代直至算出结果
- 绝大多数递归,都可以使用循环实现
- 即使递归代码很整洁,但是能不用则不用递归
04. 例题
4.1 求n的阶乘
- 代码
def fn(n):
if n == 1:
return 1
else:
return fn(n -1) * n
if __name__ == "__main__":
print(fn(6))
- 运行结果
720
4.2 将一个数逆序放入列表中,例如1234 -> list[4,3,2,1]
- 方法一
def fn(n, list1):
if len(str(n)) == 1:
list1.append(str(n))
return
else:
str1 = str(n)
list1.append(str1[-1])
str1 = str1[:-1]
fn(int(str1), list1)
if __name__ == "__main__":
list1 = []
fn(5612, list1)
print(list1)
- 运行结果
['2', '1', '6', '5']
- 方法二
def fn(num, list1):
if len(str(num)) == 1:
list1.append(num)
return list1
else:
list1.append(num % 10)
num = num // 10
return fn(num, list1)
if __name__ == "__main__":
list1 = []
fn(345689156, list1)
print(list1)
- 运行结果
[6, 5, 1, 9, 8, 6, 5, 4, 3]
4.3 猴子吃桃问题
- 一只猴子第一天摘下若干个桃子,当即吃了一半,觉得吃得不爽,又多吃了一个桃子,依次每天都是吃了一半多一个,最后到第十天只剩下1个桃子了。请问,第一天摘下多少桃子
- 解决方法
def fn(n):
if n == 1:
return 1
else:
return 2*(fn(n - 1) + 1)
if __name__ == "__main__":
print(fn(10))
- 运行结果
1534
写在最后的话:
- 无论每个知识点的难易程度如何,我都会尽力将它描绘得足够细致
- 欢迎关注我的CSDN博客,IDYS’BLOG
- 持续更新内容:
linux基础 | 数据通信(路由交换,WLAN) | Python基础 | 云计算 - 如果你有什么疑问,或者是难题。欢迎评论或者私信我。你若留言,我必回复!
- 虽然我现在还很渺小,但我会做好每一篇内容。谢谢关注!