Python 基礎之遞歸 遞歸函數 尾遞歸 斐波那契

1.遞歸函數

定義:本身調用本身的函數
:
:
有去有回是遞歸
#(1)簡單的遞歸函數
def digui(n):
    print(n)
    if n > 0:
        digui(n-1)
    print(n)

digui(5)
'''
代碼解析:
去的過程:
n = 5
print(5) 5>0 digui(5-1) => digui(4) 執行到第12行,本身調用本身,代碼暫定在12行,發生阻塞
print(4) 4>0 digui(4-1) => digui(3) 執行到第12行,本身調用本身,代碼暫定在12行,發生阻塞
print(3) 3>0 digui(3-1) => digui(2) 執行到第12行,本身調用本身,代碼暫定在12行,發生阻塞
print(2) 2>0 digui(2-1) => digui(1) 執行到第12行,本身調用本身,代碼暫定在12行,發生阻塞
print(1) 1>0 digui(1-1) => digui(0) 執行到第12行,本身調用本身,代碼暫定在12行,發生阻塞
print(0) 0>0? 條件不知足,代碼向下執行,
print(0)
若是函數執行到最後一行調用結束,要觸底反彈,回到上一層函數調用處
回的過程:
print(1) 回到函數爲1的第12 代碼繼續向下執行, print(1)
print(2) 回到函數爲1的第12 代碼繼續向下執行, print(2)
print(3) 回到函數爲1的第12 代碼繼續向下執行, print(3)
print(4) 回到函數爲1的第12 代碼繼續向下執行, print(4)
print(5) 回到函數爲1的第12 代碼繼續向下執行, print(5)
5,4,3,2,1,0,0,1,2,3,4,5


棧幀空間: 負責運行函數而開闢的空間
(1)遞歸函數總體過程,調用一層函數就是開闢一層棧幀空間,結束一層函數,就是釋放一層棧幀空間,
遞歸函數實際上就是開闢和釋放棧幀空間的過程
(2)遞歸函數回的過程:若是函數走到最後一層執行結束了,要回到上一層空間函數調用處,繼續向下執行,直到全部代碼執行完畢,
在觸發觸底反彈操做,回到上一層空間函數調用處,以此類推...
直到全部的函數全都釋放掉,那麼這個遞歸函數完全終止.
(3)寫遞歸函數的時候切記要加上一個終止的條件,不然會發生內存溢出,若是層數很少,不推薦使用遞歸

遞歸函數經過兩個條件觸發回的過程:
(1)當前函數完全執行完畢的時候,觸發回的過程,回到上一層函數的調用處
(2)當前函數遇到return 返回值的時,觸發回的過程,回到上一層函數的調用處
#計算任意數n的階乘
#5! 5*4*3*2*1
#8! 8*7*6*5*4*3*2*1
#普通方法
n = 5
total = 1
for i in range(1,n+1):
    total *= i
print(total)

#遞歸方法
def jiecheng():
    if n <= 1:
        return 1
    return n * jiecheng(n-1)

#jiecheng(1) =>1
'''
代碼解析:
去的過程:
n = 5 return 5 * jiecheng(5-1) => 5 * jiecheng(4)
n = 4 return 4 * jiecheng(4-1) => 4 * jiecheng(3)
n = 3 return 3 * jiecheng(3-1) => 3 * jiecheng(2)
n = 2 return 2 * jiecheng(2-1) => 2 * jiecheng(1)
n = 1 return 1

回的過程:
n = 2 return 2 * jiecheng(2-1) => 2*1
n = 3 return 3 * jiechneg(3-1) => 3*2*1
n = 4 return 4 * jiecheng(4-1) => 4*3*2*1
n = 5 return 5 * jiecheng(5-1) =>5*4*3*2*1

res = 5 * 4 * 3 * 2 * 1 = 120
python

2.尾遞歸

#尾遞歸:只返回遞歸函數自己且非表達式(沒有運算(+,-,*,/..))服務器

只開闢一個棧幀空間完成遞歸函數(由於最終的返回值就是第一層空間的返回值,因此只須要一層棧幀空間便可,不停的進行替換)
cpython解釋器不支持,能夠換一個支持尾遞歸的解釋器(好比在公司內部大型服務器架構的解釋器 推薦使用)
#方法一:
def jiecheng2(n,endval=1):
    if n <= 1:
        return endval
    return jiecheng2(n-1,n*endval)
res = jiecheng2(5,1)
print(res)


'''
#去的過程
n = 5 endval=1
    return jiecheng(5-1,5*1) => jiecheng(4,5*1)
n = 4 endval = 5 * 1
    return jiecheng(4-1,4* 5*1) =>jiecheng(3,4*5*1)
 n=3 endval = 4*5*1
   return jiecheng(3-1,3* 4*5*1) => jiecheng(2, 3*4*5*1)
n=2 endval = 3*4*5*1
   return jiecheng(2-1,2* 3*4*5*1) => jiecheng(1, 2*3*4*5*1)
n=1 endval = 2*3*4*5*1
   n < = 1 這個條件知足了,直接返回endval


#回的過程
n = 2 endval = 3*4*5*1
    return jiecheng(2-1,2* 3*4*5*1) => 2*3*4*5*1
n = 3 endval = 4*5*1
    return jiecheng(3-1,3* 4*5*1)   => 2*3*4*5*1
n = 4 endval = 5*1
    return jiecheng(4-1,4 *5*1) => 2*3*4*5*1
n = 5 endval = 1
     return jiecheng(5-1,5*1) => 2*3*4*5*1   

若是運行到最後一層函數,有返回值了,那麼這個返回值就是最終的值,
全部尾遞歸只須要一層棧幀空間
'''
#方法二 優化版
#系統底層用
def jiecehng2(n,endval):
    if n<=1:
        return endval
    return jiecehng2(n-1,n*endval)
#給用戶用 不須要用戶填寫第二個參數(比較人性化)
def jiecheng3(n):
    return jiecehng2(n,1)
res = jiecheng3(5)
print(res)
架構

3.斐波那契序列

# 1 1 2 3 5 8 13 21 34 55
#第n個數 它的數值是多少?
#除了前2個,後面每個值都是上一個數 + 上上的數二者之和
def fib(n):
    if n == 1 or n == 2:
        return 1

    return fib(n-1) + fib(n-2)
res = fib(45)
print(res)

'''
代碼解析:
n = 5
=> return fib(5-1) + fib(5-2)
=> return fib(4)  + fib(3) => 3 + 2 => 5
fib(4) => 3
fib(3)    +      fib(2)  = 2   + 1
fib(2) + fib(1) = 1 + 1
2+1 = 3

fib(3) => 2
fib(2)  + fib(1)
1 + 1 = 2
'''
函數

相關文章
相關標籤/搜索