第22讲:递归是神马
一 相关概念
1 定义:简单点来说,就是一个函数直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。
- 注意:递归具有危险性,很容易导致程序崩溃,所以一定要有边界条件
2 能力:用有限的语语句来定义对象的无限集合。
3 内容:一般来说,递归需要有边界条件、递归前进段和递归返回段。
- 当边界条件不满足时,递归前进;当边界条件满足时,递归返回。:
4 两个基本条件
- 函数调用自身
- 设置了正确的返回条件
5 递归深度设置
>>> import sys >>> sys.setrecursionlimit(200)
6 递归的优缺点
- 优点
- 递归的基本思想是把规模大的问题转变成规模小的问题组合,从而简化问题的解决难度(例如汉诺塔游戏)。
- 有些问题使用递归使得代码简洁易懂(例如你可以很容易的写出前中后序的二叉树遍历的递归算法,但如果要写出相应的非递归算法就不是初学者可以做到的了)
- 缺点
- 由于递归的原理是函数调用自个儿,所以一旦大量的调用函数本身空间和时间消耗是“奢侈的”。
- 初学者很容易错误的设置了返回条件,导致递归代码无休止调用,最终栈溢出,程序崩溃。
7 例子
- 汉诺塔游戏
- 斐波那契数列
- 树结构的定义
- 谢尔宾斯基三角形
- 求阶乘
- 数字三角形
- 二分查找
- 变位字(全排列)
- 目录索引
- 快速排序
二 求阶乘
1 代码:
1 """ 求阶乘 2 """ 3 # -*- coding:utf-8 -*- 4 5 """ 6 # 不用递归 7 num = int(input("请输入一个整数:")) 8 9 sum =1 10 for i in range(num+1): 11 if i > 0: 12 sum = sum * i 13 14 print ("计算结果是:%d" % sum) 15 """ 16 17 # 使用递归的思想 18 def factor(n): 19 if n==1: 20 return 1 # 当n=1的时候结束递归 21 else: 22 return n * factor(n-1) # 当n!=1的时候逐层递归,即调用factor函数本身 23 24 number = int(input("请输入一个整数:")) 25 result = factor(x) 26 print(f"{number}的阶乘结果是{result}")
2 讲解
3 补充:用递归去计算阶乘问题或斐波那契数列是很糟糕的算法,你知道为什么吗?
“普通程序员用迭代,天才程序员用递归”的意思不是说会使用递归,把所有能迭代的东西用递归来代替就是“天才程序员”了,恰好相反。因为递归的实现可以是函数自个儿调用自个儿,每次函数的调用都需要进行压栈、弹栈、保存和恢复寄存器的栈操作,所以在这上边是非常消耗时间和空间的。另外,如果递归一旦忘记了返回,或者错误的设置了返回条件,那么执行这样的递归代码就会变成一个无底洞:只进不出!
三 课后作业
1 使用递归编写一个 power() 函数模拟内建函数 pow(),即 power(x, y) 为计算并返回 x 的 y 次幂的值。
1 def power(x, y): 2 if y: 3 return x * power(x, y-1) 4 else: 5 return 1 6 7 print(power(2, 3))
2 使用递归编写一个函数,利用欧几里得算法求最大公约数,例如 gcd(x, y) 返回值为参数 x 和参数 y 的最大公约数。
1 def gcd(x, y): 2 if y: 3 return gcd(y, x%y) 4 else: 5 return x 6 7 print(gcd(4, 6))