1.什么是递归
所谓递归就是在函数定义中调用函数自身的方法,而递归的思想就是将规模大的问题转化为规模小的,具有与原来问题相同解法的问题来解决。
def func():
print('jj是很帅的')
func()
func()
# >>> maximum recursion depth exceeded while calling a Python object
# >>> 调用 Python 对象时超出最大递归深度
那么问题来了,什么是最大递归深度?
递归深度:通俗来讲就是自己调用自己的最大次数,在python中递归深度为1000,也就是说自己调用自己最多1000次,而其实,当调用次数小于1000时就已经抛出异常
count = 1
def func():
global count
print('这是第%s'%count)
count = count + 1
func()
func()
# >>> 这是第996 最大到996次
2.递归的特点
1、必须有一个明确的结束条件
2、每次进入更深一层递归时,问题规模(计算量)相比上次递归都应有所减少
3.递归的使用方法
找到递归关系,即把一个复杂的问题转化为与它形式相似、但规模较小的问题。
找到递归出口,即问题转化时,当规模足够小,可以直接求解
举个栗子:
遍历D:/Program Files文件夹,打印出所有的文件和普通文件的文件名
import os
def func(filepath,n):
files = os.listdir(filepath)
# 获取到文件的路径
for file in files:
file_p = os.path.join(filepath, file)
if os.path.isdir(file_p):
print('\t*n',file)
func(file_p,n+1)
else:
print('\t*n',file)
func("D:/Program Files",1)
4.递归的应用
(1)斐波那契数列
斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=1,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)在现代物理、准晶体结构、化学等领域,斐波那契数列都有直接的应用
代码如下:
def fab(n):
if n <= 2:
return 1
else:
return fab(n-1)+fab(n-2)
n = eval(input())
print(fab(n))
2.赶鸭子问题
题目描述
一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只。这样他经过了七个村子后还剩两只鸭子,问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子?
分析
设经过的村子为n (n = 0,1,2,...,7),根据题目分析可知递归结束的出口: n = 7时,剩余鸭子数duck = 2;
分析递归体:从后向前推 n=7时 ,duck = 2, 由于每经过一个村子,卖去所赶鸭子的一半又一只,因此七个村子后剩余的鸭子数 duck[7]=duck[6]-(duck[6]/2+1)
反推duck[6] = (duck[7] + 1) * 2
最终递归体: (duck[n+1] + 1) * 2;
代码如下:
def duck(n):
if n == 7:
return 2
else:
return (duck(n+1)+1)*2
print("鸭子的总数为:{}".format(duck(0)))
sum = duck(0)
for i in range(1, 8):
print("第{}个村庄卖出{}只鸭子,剩余鸭子数为{}". format(i, sum-duck(i), duck(i)))
sum = duck(i)
3.二分查找
在一个有序数列中,通过二分法查找出某一个数。二分法查找一次性能排除一半的元素,效率非常快,但最大的弊端在于只能针对有序数列
递归版本二分法
ls = [1,2,5,9,11,22,33,44,55,66,77,89,99,111,222]
def func(n,left,right):
print('哈哈哈')
if left < right:
mid = (left+right) // 2
if n > ls[mid]:
left = mid + 1
func(n,left,right) # 递归的入口
elif n < ls[mid]:
right = mid - 1
func(n,left,right)
elif n == ls[mid]:
print('找到了')
return mid # 通过return返回,结束递归
else:
print('没有这个数')
return -1 # 如果找不到返回-1,没有这个数。索引的起始值一般为0.
# 找n,左边界:0 右边界 len(ls) -1
ret = func(88,0,len(ls)-1)
print(ret)
# >>> None
这段代码中明确写出,如果找不到该数字,最终返回的是-1,而实际运行下来返回的是None,为什么呢?
递归是一层一层向下执行,如果最终问题解决,会返回值,而它只会返回到调用它的那一层,因此在递归时,要在每一层都加入return,才能将值返回到最外层
修改之后的代码如下:
ls = [1,2,5,9,11,22,33,44,55,66,77,89,99,111,222]
def func(n,left,right):
print('哈哈哈')
if left < right:
mid = (left+right) // 2
if n > ls[mid]:
left = mid + 1
return func(n,left,right) # 递归的入口
elif n < ls[mid]:
right = mid - 1
return func(n,left,right)
elif n == ls[mid]:
print('找到了')
return mid # 通过return返回,结束递归
else:
print('没有这个数')
return -1 # 如果找不到返回-1,没有这个数。索引的起始值一般为0.
# 找n,左边界:0 右边界 len(ls) -1
ret = func(88,0,len(ls)-1)
print(ret) # 在每一层返回,最终找不到返回-1
# >>> -1