递归函数
1、什么是递归?
从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?「从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?『从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?……』」
2、函数的嵌套调用
函数内部是可以调用其他函数的,这种调用就叫函数的嵌套调用。
而递归就是函数在其内部直接或间接调用自己。
3、Python中使用递归的注意事项
-
必须有明确的退出条件
-
每次进入更深一层递归时,问题规模比上次递归都应有所减少
-
递归效率不高,递归层数过多会导致栈溢出
在计算机中,函数调用是通过栈(stack)这种数据结构实现的。每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,就会导致栈溢出。)
查看Python中递归限制:
>>> import sys >>> sys.getrecursionlimit() 1000
4、常见应用
4.1 剥皮
def f(x): ret = [] for b in x: if isinstance(b, list): for a in f(b): ret.append(a) else: ret.append(b) return ret list2 = [11, 22, [33, 44], [55, [66, 77]], [88, [99, [100, [200, [300]]]]]] ret = f(list2) print(ret) #[11, 22, 33, 44, 55, 66, 77, 88, 99, 100, 200, 300]
4.2 二分法
# 二分查找算法:必须处理有序的列表 ################# 二分法基础版 l = [2,3,5,6,8,9,15,18,23,26,33,35,38,59,67,89,90,99] def find(l,aim): mid_index = int(len(l) // 2) if l: if l[mid_index] < aim: new_l = l[mid_index+1 :] find(new_l,aim) elif l[mid_index] > aim: new_l = l[:mid_index] find(new_l, aim) else: print('找到了',mid_index,l[mid_index]) else: print('找不到') find(l,36) # 找不到 find(l,18) # 找到了 2 18 此处的mid_index不对 ---------------------------------------------------------------------------------------- ################ 二分法升级版 def find(l,aim,start = 0,end = None): end = len(l) if end is None else end #参数end问题 mid_index = (end - start)// 2 + start # 计算中间值 if start <= end: # 针对找不到的值 if l[mid_index] < aim: return find(l,aim,start=mid_index+1,end=end) elif l[mid_index] > aim: return find(l, aim, start=start, end=mid_index-1) else: return mid_index else: return '找不到该值' l = [2,3,5,6,8,9,15,18,23,26,33,35,38,59,67,89,90,99] ret = find(l,18) print('要找的值对应的下标是:',ret) # 要找的值对应的下标是: 7
4.3 递归函数实现三级菜单
menu = { '北京':{'海淀':{'五道口':{'soho':{},'网易':{},'google':{}}, '中关村':{'爱奇艺':{},'汽车之家':'','youku':{}}, '上地':{'百度':{}} }, '昌平':{'沙河':{'老男孩':'','北航':{}}, '天通苑':{}, '回龙观':{} }, '朝阳':{}, '东城':{} }, '上海':{'闵行':{'人民广场':{'炸鸡店':{}} }, '闸北':{'火车站':{'携程':{}} }, '浦东':{} }, '山东':{} } l = [menu] # print(l[-1]) #l[-1]其实就是字典menu while l: for key in l[-1]: # l[-1]:列表最后一个元素,也就是最新的(可能是新添加的) print(key) k = input('input>>>').strip() if k in l[-1].keys() and l[-1][k]: l.append(l[-1][k]) elif k == 'b': l.pop() #pop() 函数用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。 elif k == 'q': break elif k not in l[-1].keys(): print('该地点没找到,请重新从下边列表中选择:') print('-' * 20) elif not (l[-1][k]): print('该地点下辖是空值,请重新从下边列表中选择:') print('-'*20) # 函数实现 # def threeLM(dic): # while 1: # for k in dic: # print(k) # # print(dic.keys()) #dict_keys(['北京', '上海', '山东']) # key = input('imput>>>').strip() # # print(dic[key]) #{'海淀': {'五道口': {'soho': {}, '网易': {}, 'google': {}}, '中关村': {'爱奇艺': {}, '汽车之家': '', 'youku': {}}, '上地': {'百度': {}}}, '昌平': {'沙河': {'老男孩': '', '北航': {}}, '天通苑': {}, '回龙观': {}}, '朝阳': {}, '东城': {}} # if key == 'b' or key == 'q': # return key # elif key in dic.keys() and dic[key]: # ret = threeLM(dic[key]) # if ret == 'q': # return 'q' # elif (not dic.get(key)) or (not dic[key]): # continue # # threeLM(menu) #运行结果: 北京 上海 山东 input>>>北京 海淀 昌平 朝阳 东城 input>>>昌平 沙河 天通苑 回龙观 input>>>回龙观 该地点下辖是空值,请重新从下边列表中选择: ------------------------------ 沙河 天通苑 回龙观 input>>>沙河 老男孩 北航 input>>>老男孩 该地点下辖是空值,请重新从下边列表中选择: ------------------------------ 老男孩 北航 input>>>b 沙河 天通苑 回龙观 input>>>b 海淀 昌平 朝阳 东城 input>>>b 北京 上海 山东