1. 程式人生 > 程式設計 >Python遞迴及尾遞迴優化操作例項分析

Python遞迴及尾遞迴優化操作例項分析

本文例項講述了Python遞迴及尾遞迴優化操作。分享給大家供大家參考,具體如下:

1、遞迴介紹

遞迴簡而言之就是自己呼叫自己。使用遞迴解決問題的核心就是分析出遞迴的模型,看這個問題能拆分出和自己類似的問題並且有一個遞迴出口。比如最簡單的就5的階乘,可以把它拆分成5*4!,然後求4!又可以呼叫自己,這種問題顯然可以用遞迴解決,遞迴的出口就是求1!,可以直接返回1。用Python實現如下:

def fact(n):
  if n==1:
    return n
  return n*fact(n - 1);
print(fact(5))

執行結果:

120

2、尾遞迴優化

在上面的求遞迴中,也有一定的缺點,假如說求1000!的階乘,會出現棧溢位的問題,因為在函式執行中,沒呼叫一個函式都會把當前函式的呼叫位置和內部變數儲存在棧裡面,由於棧的空間不是無限大(具體棧的最大空間還沒有查詢到),假如說呼叫層數過多,就是出現棧溢位的情況。

這個時候就可以用尾遞迴優化來解決,尾呼叫的概念非常簡單,一句話就能說清楚,就是指某個函式的最後一步是呼叫另一個函式。

function f(x){
 return g(x);
}

尾遞迴優化後的階乘函式如下:

def fact(n):
  return fact_iter(n,1);
def fact_iter(num,product):
  if num == 1:
    return product
  return fact_iter(num - 1,num * product)
print(fact(5))
print(fact(1000))

尾呼叫由於是函式的最後一步操作,所以不需要保留外層函式的呼叫記錄,因為呼叫位置、內部變數等資訊都不會再用到了。所以尾遞迴優化可以有效的防止棧溢位,但是尾遞迴優化需要編譯器或者直譯器的支援,遺憾的是,大多數程式語言沒有針對尾遞迴做優化,Python直譯器也沒有做優化,所以,即使把上面的fact(n)函式改成尾遞迴方式,也會導致棧溢位。

3、漢諾塔問題

漢諾塔問題也是一個經典的遞迴問題,具體題目就不說了,這裡分析思路。假設hanoi(n,a,b,c)實現把a上的n個盤子移到c上。

當只有一個盤子時,直接從A移動到C即可

如果有3個盤子,可以這樣:

# A --> C
# A --> B
# C --> B
# A --> C
# B --> A
# B --> C
# A --> C

如果有很多盤子,我們分析一下該怎麼移動,首先,我們需要把n-1個盤子移動到b中,才可以實現最簡單的一步,把a中最大的盤子移動到c中,具體怎麼轉移到b中後面再討論。移動最大的盤子後,a和c都可以看成是空的,接下來,把b看成是a,把a看成是b,把a中的n-1個盤子(這裡的n是已經減1的n)移動到b後,又可以移動第二大的盤子。這顯然是一個遞迴問題。

遞迴的出口就是n等於1,直接從a移動到c即可。

那麼怎麼接下來討論,怎麼把n-1個盤子移動到b,這不又是一個遞迴問題嘛!可以呼叫它自己呀,只不過需要把b看成是c,把c看成是b。所以程式碼如下:

def hanoi(n,c):
  #只有一個盤子,直接移動
  if n==1:
    print(a,'->',c)
  else:
    #通過c把n-1個盤子移動到b
    hanoi(n-1,c,b)
    #移動最大的盤子
    print(a,c)
    #通過a把n-1個盤子移動到c
    hanoi(n-1,c)
hanoi(3,'A','B','C')

執行結果:

A -> C
A -> B
C -> B
A -> C
B -> A
B -> C
A -> C

轉自https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431756044276a15558a759ec43de8e30eb0ed169fb11000

更多關於Python相關內容感興趣的讀者可檢視本站專題:《Python資料結構與演算法教程》、《Python列表(list)操作技巧總結》、《Python編碼操作技巧總結》、《Python函式使用技巧總結》、《Python字串操作技巧彙總》及《Python入門與進階經典教程》

希望本文所述對大家Python程式設計有所幫助。