什么是递归?
递归:在函数的执行过程中调用自己
5.6.1 递归的基本
- 递归的特点:
- 必须有明确的结束条件(否则会进入无限循环)
- 每次进入更深一层递归时,问题规模比上次递归都应有所减少(朝结束条件更近一步)
- 递归执行效率不高,浪费资源。所以能用迭代最好用迭代。
递归层数过多会导致栈(stack)溢出(python的递归默认1000层,这个值可修改:sys模块的getrecursionlimit())
在计算机中函数是通过栈(stack:先进后出)这种数据结果实现的。 每当一个函数调用,栈就会加一层栈帧(压栈),每当该函数返回,栈就减一层栈帧。(外层的函数会压在内层的下面) 由于栈的大小不是无限的,所以递归的层数过多会导致栈溢出。
TODO:什么是栈内存?
使用递归场景:堆排,快排,汉诺塔问题。(以后的知识点...)
- 递归例:
def calc(n): # 用递归取比n小的所有偶数
print('递归:', n)
n = int(n/2)
if n > 0:
calc(n) # 函数内调用自身来递归。会一层一层往里执行
print('出递归:', n) # 调用函数后面的语句会从最里层函数开始往外执行。因为直到最里层才会走到这行。
calc(100)
执行结果:
递归: 100
递归: 50
递归: 25
递归: 12
递归: 6
递归: 3
递归: 1
出递归: 0
出递归: 1
出递归: 3
出递归: 6
出递归: 12
出递归: 25
出递归: 50
- 扩展:栈是什么?
在计算机中,函数的调用时通过栈这种数据结构来实现的。(封装在解释器里)
那么什么是栈呢? 栈是一种先进后出的数据结构。 放在递归里来说,外层函数会最先压到栈(先进),然后依次压入其内部函数。
执行的时候,从最内层的函数开始一层一层往外执行,最外层会最后执行(后出)
5.6.2 递归的作用
- 斐波那契数列
- 汉诺塔
- 多级评论数
- 二分查找
- 求阶乘( n! = 1234...n ):思路:n! = n * (n-1)!
5.6.3 扩展:尾递归优化(递归效率的优化)(c,js有尾递归)
注意:python解释器并没有尾递归的功能,所以这里的内容跟python无关。只是一个知识的扩展。
调用下一次递归的时候,用return 只调用的函数本身
递归效率低的原因:压栈的时候,由于调用内部函数之后还有处理,所以会保留栈帧。这样会消耗资源,所以效率低。
优化:当return的只有函数结果本身,那么程序不需要保存所有的递归函数代码块,而是只要保留返回值即可。效果接近for循环。
尾递归例:
def cal(n):
print(n)
return cal(n+1) # 尾递归:直接返回下一层的函数结果,这里不能有运算。
cal(1)
非尾递归
def cal(n):
print(n)
return 1 + cal(n+1) # 由于这里还有个 '1 +'的运算在等待下一层的返回值,所以这不是尾递归。
cal(1)