递归函数


在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。

举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示,可以看出:

fact(n) = n! = 1 x 2 x 3 x ... x (n-1) x n = (n-1)! x n = fact(n-1) x n

所以,fact(n)可以表示为n x fact(n-1),只有n=1时需要特殊处理。

于是,fact(n)用递归的方式写出来就是:

def fact(n):    if n==1:        return 1    else:      sum=n*fact(n-1)    return sum

上面就是一个递归函数。可以试试:

>>> fact(5)
120
>>> fact(11)
39916800

如果我们计算fact(5),可以根据函数定义看到计算过程如下: 这里有点难理解 可以一步一步的想  一直在循环调用函数

===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120

递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。

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

>>> fact(1000)
Traceback (most recent call last):File "<pyshell#6>", line 1, in <module>fact(1000)File "C:/Users/Administrator/Desktop/10.py", line 4, in factreturn n*fact(n-1)File "C:/Users/Administrator/Desktop/10.py", line 4, in factreturn n*fact(n-1)File "C:/Users/Administrator/Desktop/10.py", line 4, in factreturn n*fact(n-1)[Previous line repeated 989 more times]File "C:/Users/Administrator/Desktop/10.py", line 2, in factif n==1:
RecursionError: maximum recursion depth exceeded in comparison

解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。

尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。

上面的fact(n)函数由于return n * fact(n - 1)引入了乘法表达式,所以就不是尾递归了。要改成尾递归方式,需要多一点代码,主要是要把每一步的乘积传入到递归函数中:

def fact(n):return fact_iter(n,1)
def fact_iter(num,product):if num==1:return productreturn fact_iter(num-1,num*product)

可以看到,return fact_iter(num - 1, num * product)仅返回递归函数本身,num - 1num * product在函数调用前就会被计算,不影响函数调用。

fact(5)对应的fact_iter(5, 1)的调用如下:

===> fact_iter(5, 1)
===> fact_iter(4, 5)
===> fact_iter(3, 20)
===> fact_iter(2, 60)
===> fact_iter(1, 120)
===> 120

尾递归调用时,如果做了优化,栈不会增长,因此,无论多少次调用也不会导致栈溢出。

遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出。

小结

使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。

针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。

Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。

转载于:https://www.cnblogs.com/-zhong/p/10863880.html

python学习之路(10)--难点相关推荐

  1. Python学习之路—2018/6/20

    Python学习之路-2018/6/20 1.模板语法之变量 views.py def index(request):import datetimes="gyq"l=[1,2,3] ...

  2. Python学习之路9☞面向对象的程序设计

    Python学习之路9☞面向对象的程序设计 一 面向对象的程序设计的由来 见概述:http://www.cnblogs.com/linhaifeng/articles/6428835.html 二 什 ...

  3. Python学习之路5☞文件处理

    Python学习之路5☞文件处理 一.文件处理流程 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件 1 正趣果上果 2 Interesting fruit fruit 3 4 ...

  4. 我的Python学习之路(一)_Mr_Ouyang

    我的Python学习之路(一)_Mr_Ouyang 笔者按: 本文从18:55开始写作,至19:38中断,又从21:12始继续,至23:22写就. 共计耗时113分钟,总字数9081字,约80.4字/ ...

  5. Python学习之路—2018/6/27

    Python学习之路-2018/6/27 1.多表操作 添加记录 添加多对多关系 方式一:传入Author对象 book = Book.objects.get(bid=1) gy = Author.o ...

  6. Python学习之路【第一篇】-Python简介和基础入门

    1.Python简介 1.1 Python是什么 相信混迹IT界的很多朋友都知道,Python是近年来最火的一个热点,没有之一.从性质上来讲它和我们熟知的C.java.php等没有什么本质的区别,也是 ...

  7. python之路 mysql 博客园_教为学:Python学习之路(二):MySQLdb的几种安装方式,以及用Python测试连接MySql...

    教为学:Python学习之路(二):MySQLdb的几种安装方式,以及用Python测试连接MySql Easy_install安装MySQLdb 很简单,以至于我不晓得该怎么说.一句话. sodu ...

  8. Python学习之路—2018/7/14

    Python学习之路-2018/7/12 3.功能开发 3.3 设计博客首页 博客首页中最重要的就是中间的文章区域,所以我首先把文章区域设计出来,一开始并没有数据,如果用orm添加或者直接在数据库添加 ...

  9. python 学习之路开始了

    python 学习之路开始了.....记录点点滴滴.... 转载于:https://www.cnblogs.com/chobit/p/6163287.html

  10. python学习之路0x00

    Python学习之路0x00 在学习python之前,要知道什么是python? python是一种跨平台的计算机程序设计语言.是一种面向对象的动态类型语言,与c语言不同, c语言要编译后才能执行.而 ...

最新文章

  1. 为什么程序员都不写文档?
  2. 任正非督战:华为强攻公有云业务 竞争残酷
  3. 深度学习 Deep LearningUFLDL 最新Tutorial 学习笔记 2:Logistic Regression
  4. easyui中combobox 验证输入的值必须为选项框中的数据
  5. docker学习笔记(七)docker-swarm
  6. 【转】c#处理3种json数据的实例
  7. CV Papers|计算机视觉论文推荐周报20200503期
  8. P1280 尼克的任务
  9. RDD文件读取与保存
  10. SQL Server 2005 技术内幕之T-SQL查询——逻辑查询处理(上)
  11. webstorm主题配置
  12. MS08067红队攻防班 第5期 开班倒计时1天~
  13. PHP一句话木马后门
  14. 破解计算机win7管理员密码,教你win7旗舰版怎么破密码
  15. 工程项目成本为什么总是管不住?关键在管理方式
  16. sort函数使用cmp出错Line 22: Char 38: error: reference to non-static member function must be called
  17. Camtasia Studio2021-激活码-序列号-秘钥中文版下载安装最新详情介绍
  18. Zookeeper C API 官方示例程序
  19. SolidWorks 钣金 焊接 管道与布线视频教程
  20. 学高数b能考计算机吗,经验 | 辞职考研上岸中南计算机

热门文章

  1. 基于HTML5功能强大的滑块幻灯片
  2. android工程下不能运行java main程序的解决办法
  3. Linux下编译android源码的步骤
  4. Report Builder:SRW包
  5. [转]六步使用ICallbackEventHandler实现无刷新回调
  6. css3的clip-path方法剪裁实现(三角形,多边形,圆,椭圆)
  7. proxool数据库连接池使用方法
  8. java基础杂谈(三)
  9. 硬核干货来啦:Js数组去重,赶快收藏吧
  10. Windows下Cesium Terrain Builder编译 (VS2015)