看完廖雪峰老师的教程,感觉尾递归函数是一个相对难点。于是复习一下,思考了一下,发表一些见解,记录一下。

1、递归函数

  在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。 例如,阶乘的实现:f(n) = n! = 1x2x3x4......xn = f(n-1) x n。因此,f(n)用递归函数写出来是:

def f(n):
if n == :
return
return f(n - ) * n

  f(5)的计算过程如下:

===> f()
===> * f()
===> * ( * f())
===> * ( * ( * f()))
===> * ( * ( * ( * f())))
===> * ( * ( * ( * )))
===> * ( * ( * ))
===> * ( * )
===> *
===>

  递归函数可以把复杂的循环,写成逻辑上容易理解的结构。但是,使用递归函数需要注意防止栈溢出。递归对系统内存的消耗是很大的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。于是,为了解决这个问题,提出了尾递归的概念。

2、尾递归函数

  尾递归是指,在函数返回的时候,return语句不能包含表达式(含加减乘除等操作),只能是递归调用。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。下面是一个示例:

def f(n):
return fact_iter(n, 1) # 返回的是另一个递归调用函数的结果 def fact_iter(num, product): # num是想要计算的值,product是结果
if num == 1:
return product
return fact_iter(num - 1, num * product) # 将乘积结果传入函数

  比较递归函数和尾递归函数,很明显的是递归函数f(n)中 return f(n - 1) * n 是一个乘法表达式,不是递归调用函数。而fact_iter(num, product)函数则不一样, return fact_iter(num - 1, num * product) 是递归调用。f(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解释器没对尾递归做优化。

  最后,汉诺塔的移动,使用递归算法,可以实现一下。我的实现如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2018-05-22 16:22:13
# @Author : Chen Jing (cjvaely@foxmail.com)
# @Link : https://github.com/Cjvaely
# @Version : $Id$ # 汉诺塔的移动可以用递归函数非常简单地实现
# 需求:打印出把所有盘子从A借助B移动到C的方法 def move(n, a, b, c):
if n == 1:
print(a, '-->', c)
else:
move(n - 1, a, c, b)
move(1, a, b, c)
move(n - 1, b, a, c) # 期待输出:
# A --> C
# A --> B
# C --> B
# A --> C
# B --> A
# B --> C
# A --> C move(3, 'A', 'B', 'C')

最新文章

  1. Fis3的前端工程化之路[三大特性篇之声明依赖]
  2. linux复制指定目录下的全部文件到另一个目录中
  3. 判断文件结束,feof……
  4. POJ 1797 Heavy Transportation(Dijkstra)
  5. JDK6 下载地址
  6. WebApi2官网学习记录---Cookie
  7. ubuntu下使用golang、qml与ubuntu sdk开发桌面应用
  8. jmeter-Java关于MD5加密方法 以及16位32位互转
  9. bzoj 3174: [Tjoi2013]拯救小矮人
  10. gulp自动化构建工具的使用
  11. oracle更改字符集为zhs16GBK
  12. linux学习笔记2 - linux常用命令
  13. JQuery invoke remote webservice
  14. Linux内核编译指定输出目录
  15. PPAS可以安装分区表
  16. 数据包式套接字:基于UDP协议的Socket网络编程
  17. Java知识点整理(三)
  18. 【[ZJOI2006]物流运输】
  19. LintCode-54.转换字符串到整数
  20. win7主题/默认账户图片路径

热门文章

  1. C 语言实例 - 循环输出26个字母
  2. Linux命令 查看Linux版本和是否联网
  3. [题解](双向bfs)hdu_3085_Nightmare Ⅱ
  4. JAVAFX-2 开发应用
  5. awk单引号处理
  6. 故障案例:主从同步报错Fatal error: The slave I/O thread stops because master and slave have equal MySQL server
  7. 函数补充:动态参数,函数嵌套,global与nonlocal关键
  8. 前端HTML以及HTML5(基本标签)
  9. uvm_reg_map——寄存器模型(八)
  10. Mysql安装报错解决办法