認識遞歸
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)