what's the python之遞歸函數、二分算法與漢諾塔游戲


what's the 遞歸?

  遞歸函數的定義:在函數里可以再調用函數,如果這個調用的函數是函數本身,那么就形成了一個遞歸函數。

  遞歸的最大深度為997,這個是程序強制定義的,997完全可以滿足一般情況下用到遞歸的情形。

#最大997層
def foo(n): print(n) n += 1 foo(n) foo(1)

 

舉個栗子:

  假設你想知道A的年齡,但你只知道A比B大2歲,B又比C大兩歲,C又比D大兩歲,D比E大兩歲,恰好你知道E的歲數,那是不是就能知道A的歲數了呢,這就可以組成一個遞歸。那我們假設E的歲數是20

def age(n): if n == 1: return 20
    else: return age(n-1)+2

print(age(5))

 

遞歸小練習

def func1(x):
    print(x)
    func1(x-1)

def func2(x):
    if x>0:
        print(x)
        func2(x-1)

def func3(x):
    if x>0:
        func3(x-1)
        print(x)
        
func1(5)    #死循環
func2(5)    #5 4 3 2 1
func3(5)    #1 2 3 4 5
練習1
def test(n):
    if n == 0:
        print("我的小鯉魚", end='')
    else:
        print("抱着", end='')
        test(n-1)
        print("的我", end='')
def func(n):
    print('嚇得我抱起了', end='')
    test(n)

func(3)#嚇得我抱起了抱着抱着抱着我的小鯉魚的我的我的我
練習2(嚇得我抱起了抱着抱着抱着我的小鯉魚的我的我的我)

 

二分算法

  遞歸函數的一個經典用法就是二分算法,二分算法的意思是用對半切查找的方式從由一群由小到大的數組成的列表中找到要找的數字的方法

舉個栗子:

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 func(l,aim):                          def func(l, aim,start = 0,end = len(l)-1 ):                                 
    mid = (len(l)-1)//2                     mid = (start+end)//2
    if l:                                     if not l[start:end+1]:
        if aim > l[mid]:                       return
            func(l[mid+1:],aim)             elif aim > l[mid]:
        elif aim < l[mid]:                     return func(l,aim,mid+1,end)
            func(l[:mid],aim)               elif aim < l[mid]:
        elif aim == l[mid]:                   return func(l,aim,start,mid-1)
            print("bingo",mid)              elif aim == l[mid]:
    else:                                         print("bingo")
        print('找不到')                            return mid
func(l,66)                                index = func(l,68)
func(l,6)                                 print(index)

 

以上就是簡單的二分算法,當然因為切片會造成內存的損耗,所以我們還可以將以上代碼進行改進

def bin_search_rec(data_set,value,low,high):
    if low <= high:
        mid=(low+high) // 2
        if data_set[mid] == value:
            return mid
        elif data_set[mid] > value:
            return bin_search_rec(data_set,value,low,mid-1)
        else:
            return bin_search_rec(data_set,value,mid+1,high)
    else:return None

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]
a=bin_search_rec(l,66,2,88) 
print(a)#2

 

漢諾塔游戲

  漢諾塔游戲是法國數學家愛德華·盧卡斯編寫的一個印度的古老傳說:大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞着64片黃金圓盤。 大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。 在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤。 64根柱子移動完畢之日,就是世界毀滅之時。

 

   這個游戲可以用遞歸的思想解決,首先我們來捋一捋思路:

      兩個盤子時:

      1. 把小圓盤從A移動到B
      2. 把大圓盤從A移動到C
      3. 把小圓盤從B移動到C

      n個盤子時:

      1. 把n-1個圓盤(除去最后一個以外的所有)從A經過C移動到B
      2. 把第n個圓盤(最后一個)從A移動到C
      3. 把n-1個小圓盤從B經過A移動到C

 接下來我們來寫代碼

a=0
def hanoi(n,x,y,z):
    global a
    if n==1:
        a+=1
        print(x,'-->',z)
    else:
        hanoi(n-1,x,z,y)#將前n-1個盤子從x移動到y上
        hanoi(1,x,y,z)#將最底下的最后一個盤子從x移動到z上
        hanoi(n-1,y,x,z)#將y上的n-1個盤子移動到z上

n=int(input('請輸入漢諾塔的層數:'))

hanoi(n,'柱子A','柱子B','柱子C')
print('一共用了%s次'%a)
"""
假設我們的漢諾塔層數為3
請輸入漢諾塔的層數:3
柱子A --> 柱子C
柱子A --> 柱子B
柱子C --> 柱子B
柱子A --> 柱子C
柱子B --> 柱子A
柱子B --> 柱子C
柱子A --> 柱子C
一共用了7次
"""

 

  漢諾塔移動次數的遞推式:h(x)=2h(x-1)+1。h(64)=18446744073709551615 假設婆羅門每秒鍾搬一個盤子,則總共需要5800億年!所以世界是不會毀滅的哇咔咔~

 


免責聲明!

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



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