python之路18--之递归与使用递归实现二分查找算法
认识递归
1、什么是递归函数:
在自身函数里调用自己,就是递归函数,python系统默认最大递归次数为998次,超过了这个次数会报如下错误(RecursionError: maximum recursion depth exceeded while calling a Python object),写递归时一定要写结束条件!!
1.1、递归的返回值:
不要只看到return就认为已经返回了,要看返回操作是在递归到几层的时候发生的,然后返回给了谁
如果不是返回给外层函数,调用者就接收不到
需要再分析,看如何把结果返回回来
2、如何修改默认递归得次数:
不建议修改,如果递归次数太多就不适合用递归来解决
import sys sys.setrecursionlimit(10000)
3、递归得优缺点:
优点:会让代码变简单
缺点:占内存
一个递归计算年龄的例子及递归得运行过程
需求:
求欧阳多大了
已知:欧阳比张三大两岁,
张三比李四大两岁,
李四比二麻子大两岁
二麻子今年40了
递归得代码:求欧阳今年多大了:
def age(n): if n == 4: return 40 elif n > 0 and n < 4: return age(n+1)+2 print(age(1)) #最终计算结果:46
上面得递归代码运行得过程:
第一次递归,执行函数时将1当实参传进来了 def age(1): if 1 == 4: return 40 elif 1 > 0 and 1 < 4: return age(1+1)+2 #age(2+2 #44+2==46最终结果为:46 def age(2): if 2 == 4: return 40 elif 2 > 0 and 2 < 4: return age(2+1)+2 #age(3)+2 #42+2==44 def age(3): if 3 == 4: return 40 elif 3 > 0 and 3 < 4: return age(3+1)+2 #age(4)+2 #40+2==42 def age(4): if 4 == 4: #n==4时 return 40 #返回40 elif 3 > 0 and 3 < 4: #不符合这里得条件,一下代码不执行 return age(3+1)+2
画图说明执行过程:
一个递归计算斐波那契数列的例子及递归的过程
斐波那契数列说明(第一位和第二位都是1,以后的每个数字是前两个数字相加的合):1,1,2,3,5,8,13,21,34,55,89
1、使用双调用的形式计算斐波那契数列
def fib(n): if n == 1 or n == 2: return 1 return fib(n-1) +fib(n-2) print(fib(5))
1.1、递归方式
第一次递归的过程 def fib(5): if n == 1 or n == 2: #向下递归 #向上预算结果 return 1 return fib(n-1) +fib(n-2) #fib(5-1) + fib(5-2) #3+2=5 print(fib(5)) #结果为5 第二次递归得过程 def fib(4): if n == 1 or n == 2: return 1 return fib(n-1) +fib(n-2) #fib(4-1) + fib(4-2) #2+1=3 print(fib(4)) #结果为:3 def fib(3): if n == 1 or n == 2: return 1 return fib(n-1) +fib(n-2) #fib(3-1) + fib(3-2) #1+1=2 print(fib(3)) #结果为:2 第三次递归的过程 def fib(3): if n == 1 or n == 2: return 1 return fib(n-1) +fib(n-2) #fib(3-1) + fib(3-2) print(fib(3)) def fib(2): if n == 1 or n == 2: return 1 #返回1 return fib(n-1) +fib(n-2) print(fib(2)) def fib(1): if n == 1 or n == 2: return 1 #返回1 return fib(n-1) +fib(n-2) print(fib(1))
说明:双递归的方式计算斐波那契数列效率很慢,因为递归里设计到两次函数调用,每个函数每次调用都要重新计算一下,具体看下图详解
2、使用但调用的形式计算斐波那契数列
#一次调用计算斐波那契数列 def fib(n): if n == 2: return 1,1 else: a,b = fib(n-1) print(a,b) return b,a+b print(fib(4)) #结果为前一个数字和计算结果(不完美) #修改后(只显示计算出的斐波那契数列 完美的) def fib(n,l = [0]): l[0] +=1 if n == 1 or n == 2: l[0] -= 1 return 1,1 else: a,b = fib(n-1) l[0] -= 1 if l[0] == 0: return a+b return b,a+b print(fib(4))
2.1、递归过程说明:
def fib(n): if n == 2: return 1,1 else: a,b = fib(n-1) print(a,b) return b,a+b print(fib(4)) #最终结果为(2,3) #第一次递归 def fib(4): if 4 == 2: #0、条件不成立 return 1,1 else: a,b = fib(4-1) #1、4-1=3 #8、a=1,b=2 return b,a+b #9、返回值2,3 print(fib(4)) #第二次递归 def fib(4): if 4 == 2: #2、条件不成立 return 1,1 else: a,b = fib(4-1) #3、3-1=2 #6、a=1,b=1 return b,a+b #7、返回值1,2 print(fib(4)) #第三次递归 def fib(4): if 4 == 2: #4、条件成立 return 1,1 #5、返回1,1 else: a,b = fib(4-1) return b,a+b print(fib(4))
算法
什么叫算法:计算的方法:人脑复杂,计算机简单
查找:找数据
排序:找最短路径
现在学习的算法都是过去式
了解基础的算法才能创造出更好的算法
不是所有的事情都能套用现成的方法解决的
有些时候用到学过的算法知识来解决新的问题
二分查找算法
二分查找算法,必须处理有序的列表
使用递归实现二分查找算法:
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] def find(l,aim,start = 0,end = None): end = len(l) if end is None else 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 print(\'找到了,index为:%s\'%mid_index,) else: return \'找不到这个值...\' ret = find(l,44) print(ret)
递归实现的过程
#第一次递归 def find(l,aim,start = 0,end = None): end = len(l) if end is None else end #end = len(l) -->25 mid_index = (end - start) // 2 + start #计算中间值 25 // 2 == 12 + 0 == 12 if l[mid_index] < aim: #12和目标作比较,12 < 44 find(l,aim,start = mid_index+1,end=end) #find (l,44,start=13,end=24) elif l[mid_index] > aim: find(l,aim,start=start,end=mid_index-1) else: print(\'找到了\',mid_index,aim) find(l,44) #第二次递归 def find(l,aim,start = 0,end = None): #find(l,44,start = 13,end = 24) end = len(l) if end is None else end #end 不等于空,所以end = 24 mid_index = (end - start) // 2 + start #计算中间值 (24 - 13) // 2 == 5 + 13 == 18 if l[mid_index] < aim: #18和目标作比较,l[18] == 67,67和44比较 find(l,aim,start = mid_index+1,end=end) elif l[mid_index] > aim: #67 > 44 find(l,aim,start=start,end=mid_index-1) #find (l,44,start=13,end=18 - 1) else: print(\'找到了\',mid_index,aim) #第三次递归 def find(l,aim,start = 0,end = None): #find(l,44,start = 13,end = 17) end = len(l) if end is None else end #end 不等于空,所以end = 17 mid_index = (end - start) // 2 + start #计算中间值 (17 - 13) // 2 == 2 + 13 == 15 if l[mid_index] < aim: #15和目标作比较,l[15] == 55,55和44比较 find(l,aim,start = mid_index+1,end=end) elif l[mid_index] > aim: #55 > 44 find(l,aim,start=start,end=mid_index-1) #find (l,44,start=13,end=15 - 1) else: print(\'找到了\',mid_index,aim) #第四次递归 def find(l,aim,start = 0,end = None): #find(l,44,start = 13,end = 14) end = len(l) if end is None else end #end 不等于空,所以end = 14 mid_index = (end - start) // 2 + start #计算中间值 (14 - 13) // 2 == 0 + 13 == 13 if l[mid_index] < aim: #13和目标作比较,l[13] == 42,42和44比较,42 <44 find(l,aim,start = mid_index+1,end=end) #find (l,44,start=14,end=14) elif l[mid_index] > aim: find(l,aim,start=start,end=mid_index-1) else: print(\'找到了\',mid_index,aim) #第五次递归 def find(l,aim,start = 0,end = None): #find(l,44,start = 14,end = 14) end = len(l) if end is None else end #end 不等于空,所以end = 14 mid_index = (end - start) // 2 + start #计算中间值 (14 - 14) // 2 == 0 + 13 == 13 if l[mid_index] < aim: #13和目标作比较,l[13] == 42,42和44比较,42 <44 find(l,aim,start = mid_index+1,end=end) #find (l,44,start=15,end=14) #start大于end时预示着找不到了 elif l[mid_index] > aim: find(l,aim,start=start,end=mid_index-1) else: print(\'找到了\',mid_index,aim)