1.初识递归函数
1.什么是递归函数:
在函数内部有直接或间接调用函数本身的函数就是递归函数,例如:
def fun_test():
return fun_test() # 在函数内部调用函数本身
fun_test()
当然,执行这段代码时会出现报错:
RecursionError: maximum recursion depth exceeded
翻译过来就是:递归错误:超出最大递归深度,同时会出现如下提示:
从这里我们可以看出:调用超过996/997次就会出现报错,因此,python中默认的递归深度不超过1000,这是为了保护内存,当然,我们也可以自己修改递归深度,修改递归深度的方法如下:
import sys
sys.setrecursionlimit(100000) # 参数就是你想要的递归深度
但是不建议自己修改递归深度,因为如果递归次数过多,那就说明不适合使用递归实现。
递归的优势在于:减少代码的冗余,让代码更简洁。
递归的缺点在于:占内存
2.递归函数的执行
递归二字,其实可以分开来解读,即:传递过程 和 回归过程,传递过程就是函数的调用过程,回归过程就是返回值返回的过程,我们使用一个例子来进行说明:
def age(n):
if n==4:
return 30
elif n>0 and n<4:
return age(n+1)+2 # 在此处调用了函数本身
print(age(1))
此函数的执行过程如下所示:
3.递归函数的实例 - 二分查找算法
如果我们需要在数组中查询一个数,即:输入数字,返回此数字在数组中的下标,最简单也是最容易想到的方法就是遍历数组,但是遍历也是最耗时的方法,如果有100w个数,而我们所需查找的数刚好是最后一个,那我们就需要循环100w次才能找到。
二分查找算法的思想是:
对于一个有序的数组,设置最开始的搜索区间是整个数组,区间左端点为0,右端点是数组长度,取搜索区间的中间值,将所要查找的值与中间值进行比较,如果刚好相等,那么一次就找到了;如果比中间值大,那说明我们所需查找的值在右边,那么我们将区间左边往右移动,即将区间左端点设置为中间值的索引,此时搜索区间长度就缩短为原来的一半,同理,如果比中间值小,那说明我们所需查找的值在左边,那么我们将区间右边往左移动,即将区间右端点设置为中间值的索引,再在新的搜索区间重复上面步骤进行查找,知道找到为止。
实现代码如下:
def binary_serarch(l,aim,start_index=0,end_index=None):
'''
函数用来实现二分查找固定的值
:param l: l 是原始的参数,需要注意的是 l 的值需要一直保持不变,否则下标就会改变了
:param aim: aim 是需要查找的目标
:param start_index: 从 l 中开始查找的下标
:param end_index: 从 l 中结束查找的下标位置
需要注意的是,此值默认是None,本来应该是列表l的长度,但是不能直接 end_index = len(l)
来设置默认值,因为 l 不是一个已知的,它是一个未知的参数,所以此值应该默认为None再重新赋值
:return:
'''
end_index = len(l) if end_index is None else end_index
# 如果是第一次调用的默认参数则将搜索区间右边设置为数组长度,否则维持原值不变
# 即,第一次搜索区间为整个数组
mid_index = (end_index-start_index)//2 + start_index # 此值是中间下标
if start_index <= end_index: # 如果开始的下标小于结束的下标,说明还有寻找的空间,则继续寻找
if l[mid_index]>aim: # 如果列表中间的值比目标值大,说明目标值在左边
return binary_serarch(l,aim,start_index=start_index,end_index=mid_index-1)
# 那么将搜素区间结束位置左移,由于 l[mid_index] 已经做过比较,因此不再做比较,下标值减一
# 注意已经要 return,否则递归到此处没有接收返回值会返回None
# 注意,不需要改变的参数也要传递,不传参会有默认参数...
if l[mid_index]<aim: # 如果列表中间的值比目标值小,说明目标值在右边
return binary_serarch(l,aim,start_index=mid_index+1,end_index=end_index)
else: # 如果中间值与aim相等,则直接返回
return mid_index
else: # 如果开始的下标小于结束的下标,说明已经全部搜索完毕且没找到,则返回一个字符串
return 'No such number.'
l = [2, 3, 5, 10, 15, 16, 18, 22, 26, 30, 32, 35, 41, 42, 43, 55, 56, 66, 67, 69, 72, 76, 82, 83, 88]
ret = binary_serarch(l,30)
print(ret)