一、递归的定义
函数的递归调用:是函数嵌套调用的一种特殊形式
具体是指:
在调用一个函数的过程中又直接或者间接地调用到本身
# 直接调用本身 def f1(): print('是我是我还是我') f1() f1()
# 间接接调用本身 def f1(): print('===>f1') f2() def f2(): print('===>f2') f1() f1()
# 一段代码的循环运行的方案有两种 # 方式一:while、for循环 while True: print(1111) print(2222) print(3333) # 方式二:递归的本质就是循环: def f1(): print(1111) print(2222) print(3333) f1() f1()
二、递归的结束
递归调用不应该无限地调用下去,必须在满足某种条件下结束递归调用
n=0 while n < 10: # 设置循环结束条件 print(n) n+=1 def f1(n): if n == 10: # 设置递归结束条件 return print(n) n+=1 f1(n) f1(0)
补充:
''' 1. 可以使用sys.getrecursionlimit()去查看递归深度,默认值为1000,虽然可以使用 sys.setrecursionlimit()去设定该值,但仍受限于主机操作系统栈大小的限制 2. python不是一门函数式编程语言,无法对递归进行尾递归优化。 '''
三、递归的两个阶段
回溯:一层一层调用下去
递推:满足某种条件,结束递归,然后一层一层返回
# salry(4) = age(3) + 1000 # salry(3) = age(2) + 1000 # salry(2) = age(1) + 1000 # salry(1) = 5000 def salary(n): if n == 1: return 5000 return age(n-1) + 1000 res=age(4) print(res) # 8000
四、递归应用
4.1 嵌套列表的取值(计算文件夹大小也可这么操作):
l=[1,2,[3,[4,[5,[6,[7,[8,[9,10,11,[12,[13,]]]]]]]]]] def f1(list1): for x in list1: if type(x) is list: # 如果是列表,应该再循环、再判断,即重新运行本身的代码 f1(x) else: print(x) f1(l)
4.2 斐波拉契数列
法一:函数递归得到第n项斐波拉契数列,循环函数得到数列
def print_Fibonacci(n): for i in range(1,n+1): print(Fibonacci(i),end=" ") print() def Fibonacci(n): if n == 1 or n == 2: return n-1 elif n > 2: return Fibonacci(n-2) + Fibonacci(n-1) return -1 print(Fibonacci(15)) print_Fibonacci(15)
法二:设定数列初始的两个值与数列终止值,每次替换初始值为平移一个单位后的两个值,并打印
def fib(a,b,c): if a > c: return print(a,end=" ") fib(b,a+b,c) fib(0,1,388)
法三:非递归方法实现
def fib2(max): a=0 b=1 while a< max: yield a a, b=b, a+b g = fib2(500) for i in g: print(i,end=" ")
4.3 汉诺塔
def hannuota(n,A="A",B="B",C="C"): if n == 1: print(f"将第{n}块积木从{A}柱放到{C}柱") return hannuota(n-1,A,C,B) print(f"将{n}块积木从{A}柱子放到{C}柱子") hannuota(n-1,B,A,C) n = input("请输入汉诺塔层数:") if n.isdigit(): n = int(n) hannuota(n) else: print("请输入数字")
五、查找与排序
5.1 二分法
算法:是高效解决问题的办法
算法之二分法
需求:有一个按照从小到大顺序排列的数字列表
需要从该数字列表中找到我们想要的那个一个数字
如何做更高效???
方案一:整体遍历---效率太低
for num in nums: if num == find_num: print('find it') break
方案二:二分法
思路:
def binary_search(find_num,列表): mid_val=找列表中间的值 if find_num > mid_val: # 接下来的查找应该是在列表的右半部分 列表=列表切片右半部分 binary_search(find_num,列表) elif find_num < mid_val: # 接下来的查找应该是在列表的左半部分 列表=列表切片左半部分 binary_search(find_num,列表) else: print('find it')
实现:
nums=[-3,4,7,10,13,21,43,77,89] find_num=8 def binary_search(find_num,l): print(l) if len(l) == 0: print('找的值不存在') return mid_index=len(l) // 2 if find_num > l[mid_index]: # 接下来的查找应该是在列表的右半部分 l=l[mid_index+1:] binary_search(find_num,l) elif find_num < l[mid_index]: # 接下来的查找应该是在列表的左半部分 l=l[:mid_index] binary_search(find_num,l) else: print('find it') binary_search(find_num,nums)
5.2 快速排序
l = [12,5,48,99,37,26,0,7,51] def Sort(l,low,high):
flag = l[low] i = low j = high # 若i<j 则需要继续找flag位置,并递归 if i < j: # 循环查找,直到i=j,找到flag位置 while i < j: while i < j and l[j] >= flag: j -= 1 if i < j: l[i] = l[j] i += 1 while i < j and l[i] <= flag: i += 1 if i < j: l[j] = l[i] j -= 1 l[i] = flag # if i == low: # # Sort(l,low,i-1) # Sort(l,i+1,high) # elif i == high: # Sort(l,low,i-1) # # Sort(l, i + 1, high) # else: # Sort(l,low,i-1) # Sort(l, i+1, high) if low < i -1: # 若 low < i-1 则至少还有两个元素,继续进行排序。若只有一个则不再进入递归,开始往回递推 Sort(l,low,i-1) if high > i+1: # 同上 Sort(l, i + 1, high) print(l[0]) Sort(l,0,len(l)-1) print(l)