遞歸的概念:函數包含了對自身的調用,那麼就是遞歸,函數運行會佔用內存。
使用的場景:若是你發現你將要作的事情就是你如今作的,那麼用遞歸
遞歸相似循環;在編寫或閱讀遞歸時,首先咱們關注的是遞歸的終止條件python
##########33 def zhangan(index=0): if index < 100: print('當前運行的此時',index) return zhangan(index+1) else: print('遞歸結束') return 1 rt = zhangan() print('返回值:',rt)
當前運行的此時 95 當前運行的此時 96 當前運行的此時 97 當前運行的此時 98 當前運行的此時 99 遞歸結束 返回值: 1
在接觸遞歸以前,咱們先來作這麼一個問題:若是說,要對一個數字列表求和(或者其餘序列)求和,除了咱們可使用內置的sum函數,還有什麼辦法?
若是你還有更優秀的辦法,能夠在關於頁面找到個人聯繫方式,有償提交給我函數while循環:ui
1 L = [1,2,3,4,5] 2 mysum = 0 #保存和的變量 3 while L: #將列表最爲循環條件 4 mysum += L[0] #每次將列表第一個位置的值加到和中 5 L = L[1:] #去掉列表第一個元素
for循環:spa
1 L = [1,2,3,4,5] 2 mysum = 0 3 for var in L: 4 mysum += var
遞歸求和:code
1 a = [1,2,3,4,5] 2 def zhangan(seq): 3 if not seq: #空列表時遞歸終止返回值0 4 return 0 5 else: 6 return seq[0]+zhangan(seq[1:]) 7 #在返回值中,咱們返回了一個函數的調用,而且傳遞的參數爲去掉當前列表第一個元素的新列表 8 print(zhangan(a))
1 a = [1,2,3,4,5] 2 def get_sum(seq): 3 if seq: 4 return seq[0] + get_sum(seq[1:]) 5 else: #空列表時遞歸終止 6 return 0 7 #return seq[0] + get_sum(seq[1:]) if seq else 0 8 rt = get_sum(a) 9 print(rt) 10 1#get_sum([1,2,3,4,5]): return 1 + get_sum([2,3,4,5]) 11 2#get_sum([2,3,4,5]) : return 2 + get_sum([3,4,5]) 12 3#get_sum([3,4,5]) : return 3 + get_sum([4,5]) 13 4#get_sum([4,5]) : return 4 + get_sum([5]) 14 5#get_sum([5]) : return 5 + get_sum([]) 15 6#get([]) : return 0
遞歸處理非線性循環blog
遞歸還能夠處理一些非線性循環,而普通的循環是沒法處理的
好比這樣一個列表對其求和:遞歸L = [1,[2,[3,4],5],6,[7,8]]
因爲這個列表不是一個線性迭代,包含着複雜的元素嵌套
普通的循環語句處理起來將會很是難以控制遊戲
1 L = [1,[2,[3,4],5],6,[7,8]] 2 sum = 0 3 def mysum(L): 4 global sum 5 for var in L: 6 if not isinstance(var,list): 7 #若是其中元素不爲列表類型,則爲一個肯定的值 8 sum += var 9 else: 10 mysum(var) 11 return
第一種用global運算:內存
1 mylist = [1,2,[3],5,[6,[7,8,9]],1,2] #-> 44 2 #試一下用循環求和, 3 #若是列表變化,那麼代碼能夠兼容,能夠直接複用,不能改變 4 mysum = 0 5 #for while 一層層的向下遍歷 6 7 def get_sum(iter):#接收一個等待求和的多層序列 8 #iter 中 無非兩種數據類型: list int 9 global mysum 10 for var in iter: 11 if type(var) == int: #當前取出來的數據是int 12 #if type(var) == type([]) 13 mysum += var 14 else: 15 get_sum(var) #遇到的又是一個列表,那麼咱們繼續遍歷 16 #for循環結束的時候,遞歸結束 17 get_sum(mylist) 18 print(mysum) 19 # get_sum([1,2,[3],5,[6,[7,8,9]],1,2]) 20 #mysum += 1,2,5,1,2 21 # get_sum([3]) -> mysum += 3 22 # get_sum([6,[7,8,9]]) 23 #mysum += 6 24 # get_sum([7,8,9]) 25 #mysum += 7,8,9
第二種用return返回值求和: 作用域
1 a = [1,2,[1,2,3],5,[6,[6,7,8,9]],32,2] 2 def zhangan(a1): 3 sum = 0 #每一次遞歸sum都爲0 4 for var in a1: 5 if type(var) == int: 6 sum += var 7 else: 8 dsum = zhangan(var) #每一次list遞歸的結果 9 sum = sum + dsum #遞歸的結果值和不走遞歸的結果值加起來 10 return sum #函數運行結果要返回 11 rt=zhangan(a) 12 print(rt)
花錢遞歸
思考:假如你有10000塊,天天花一半,毛錢直接捨棄,那麼這錢能夠花幾天?
遞歸解決:
1 money = 10000 2 def zhangan(money,day=1): 3 if money > 0: 4 print('今天是第:%d天' % day) 5 money1 = money // 2 #每次花一半 6 print('還剩餘:%d' % money1) 7 day +=1 #花完天數+1 8 return zhangan(money1,day) 9 else: 10 return day 11 print(zhangan(money))
1 moeny = 10000 2 def func(moeny,day=0): 3 if moeny > 0: 4 func(moeny // 2,day+1) 5 else: 6 print(day) 7 return 0 8 func(moeny)
小猴子吃桃子遞歸:
1 #小猴子吃桃子 2 #100個桃子,天天吃一半加一個,何時不能按照這樣的條件吃了。得花多少天 3 4 peach_num = 100 5 def eat_peach(peach_num,day = 1): 6 print('今天是%d天' % day) 7 print('如今還有%d個桃子' % (peach_num)) 8 eat_num = peach_num // 2 + 1 9 peach_num = peach_num - eat_num 10 if peach_num > 0: 11 print('吃完了還剩下%d個桃子' % (peach_num)) 12 day += 1 13 print('--------------') 14 return eat_peach(peach_num, day) 15 else: 16 return day 17 day = eat_peach(peach_num) 18 print(day) 19 20 1#eat_peach(100,day = 1): 21 ''' 22 eat_num = 51 要吃的 23 peach_num = 49 剩下的 >0 24 day = 1 當前的天數 25 return eat_peach(49, 2) 6 26 ''' 27 2#eat_peach(49, 2) 28 ''' 29 eat_num = 25 要吃的 30 peach_num = 24 剩下的 >0 31 day = 2 當前的天數 32 return eat_peach(24, 3) 6 33 ''' 34 3#eat_peach(24, 3) 35 ''' 36 eat_num = 13 要吃的 37 peach_num = 11 剩下的 >0 38 day = 3 當前的天數 39 return eat_peach(11, 4) 6 40 ''' 41 4#eat_peach(11, 4) 42 ''' 43 eat_num = 6 要吃的 44 peach_num = 5 剩下的 >0 45 day = 4 當前的天數 46 return eat_peach(5, 5) 6 47 ''' 48 5#eat_peach(5, 5) 49 ''' 50 eat_num = 3 要吃的 51 peach_num = 2 剩下的 >0 52 day = 5 當前的天數 53 return eat_peach(2, 6) 6 54 ''' 55 6#eat_peach(2, 6) 56 ''' 57 到了這一天,無法過了! 58 eat_num = 2 要吃的 59 peach_num = 0 剩下的 = 0 60 day = 6 當前的天數 61 return 6 62 '''
1 #小猴子吃桃子 2 #100個桃子,天天吃一半加一個,何時不能按照這樣的條件吃了。得花多少天 3 taozi = 100 4 def func(taozi,day=1): 5 if taozi > 0: 6 eat_num = taozi // 2 + 1 7 sum_num = taozi - eat_num 8 day +=1 9 func(sum_num,day) 10 else: 11 print(day) 12 return 0 13 func(taozi)
統計每個出現的字符出現的次數:
1 mylist = ['asdazxc','adxzc',['12390145fcsdjfhzkjxcmnasd','123987189asjkdsajkb'],'asdqwewqerq',['asd890q8390'],'asdhquiweqysa','asdhjkzhxjkckjasdh'] 2 #把同樣的提出來 3 #統計每個出現的字符出現的次數 4 #for循環實現 5 dict_num = {} 6 #key:對應的字符 7 #value:出現的次數 8 def get_num(seq): 9 #字典是可變數據類型,因此直接能夠在函數做用域內進行修改 10 for var in seq: #遍歷整個列表數據 11 if type(var) == list: 12 #若是取出來的仍是一個列表,那麼就繼續遞歸 13 get_num(var) 14 else: #若是碰到的是一個字符串 15 for i in var: #遍歷字符串,記錄次數 16 if i in dict_num: 17 # 若是獲取到的字符,已經存在了字典中,那麼他的次數+1 18 dict_num[i] = dict_num[i] + 1 19 else: 20 # 若是獲取到的字符沒出現過,那麼就建立默認值1就行 21 dict_num[i] = 1 22 get_num(mylist) 23 for key in dict_num: 24 print(key,':',dict_num[key])
1 mylist = ['asdazxc','adxzc',['12390145fcsdjfhzkjxcmnasd','123987189asjkdsajkb'],'asdqwewqerq',['asd890q8390'],'asdhquiweqysa','asdhjkzhxjkckjasdh'] 2 sum_dict = {} 3 def func(seq): 4 for var in seq: 5 if type(var) == str: 6 for i in var: 7 if sum_dict.get(i): 8 sum_dict[i] = sum_dict[i]+1 9 else: 10 sum_dict[i] = 1 11 else: 12 func(var) 13 func(mylist) 14 print(sum_dict)
腳本模擬環境 爲如今很火的遊戲 病毒公司
1, 有一種高繁殖 高傳播(只限空氣與水) 難治癒 但不危機生命的病毒
2, 腳本測算它的傳播速度
3, 假設一個城市有1000萬人口 日出生率與死亡率抵消後人口增加率爲日10萬分之一
4, 病毒最初只有一個,以天天一倍的速度繁殖
5, 每1萬個病毒能夠感染一個病人
計算多少天能夠感染全市人.
import time import os def func(day,viruses,population): day += 1 viruses += viruses population = round(population * 1.00001) if viruses // 10000 > population: print('\n\n今天是第%s天,全市的人均可能會被感染,因此請在此時間前研究出疫苗' % day) return print('今天是第%s 天 , 有細菌 %s 個 人口 %s' % (day,viruses,population)) time.sleep(1) os.system('cls') return func(day,viruses,population) func(0,1,10000000)
遞歸注意事項
Python中,遞歸的最大上限次數差很少是1000次左右
一個沒有終止條件的遞歸會引起錯誤(相似一個死循環)
這是由於遞歸的每一次函數執行*,都會在內存中產生新的函數副本,遞歸的內存消耗要大於普通循環;可是一樣的,消耗了內存,效率高**於普通循環
1 >>> def func(): 2 ... return func() 3 ... 4 >>> func() 5 Traceback (most recent call last): 6 File "<stdin>", line 1, in <module> 7 File "<stdin>", line 2, in func 8 File "<stdin>", line 2, in func 9 File "<stdin>", line 2, in func 10 [Previous line repeated 995 more times] 11 RecursionError: maximum recursion depth exceeded 12 #這裏咱們在995次遞歸以後,達到上線,從而報錯
咱們也能夠手動干預遞歸的上限,可是這是有風險的,要結合計算機自己內存來考慮
1 >>> import sys 2 >>> sys.setrecursionlimit(num)在這裏,num即爲你想控制修改的最大遞歸上限次數