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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM