scala學習:遞歸/尾遞歸

遞歸: 函數

例子4:上臺階 優化

N級臺階,便可每次1步也可每次2步走,共有多少種不一樣走法 spa

解法:邁出第一步有兩種方法,第一步後就是N-1N-2的走法了 遞歸

def step(n:Int):Int = if (n<=2) n else step(n-1)+step(n-2) ci

推廣:若是每次可走1步或2步或3步,則 資源

def step(n:Int):Int = n match { case 1=>1; case 2=>2; case 3=>4; table

case _ =>step(n-1)+step(n-2)+step(n-3) } 循環

尾遞歸:

定義:函數尾(最後一條語句)是遞歸調用的函數。 方法

tail-recursive會被優化成循環,因此沒有堆棧溢出的問題。 數據

 

線性遞歸的階乘:

def nn1(n:Int):BigInt = if (n==0) 1 else nn1(n-1)*n

println(nn1(1000)) // 4023...000

println(nn1(10000)) // 崩潰:(

 

尾遞歸的階乘:

def nn2(n:Int, rt:BigInt):BigInt = if (n==0) rt else nn2(n-1, rt*n)

println(nn2(1000,1)) // 40...8896

println(nn2(10000,1)) // 2846...000

 

def nn3(n:Int):BigInt = nn2(n,1)

 

對比:

線性遞歸

尾遞歸

nn1(5) 
{5 * nn1(4) }
{5 * {4 * nn1(3) }}
{5 * {4 * {3 * nn1(2) }}}
{5 * {4 * {3 * {2 * nn1(1) }}}}
{5 * {4 * {3 * {2 * 1}}}}
{5 * {4 * {3 * 2}}}
{5 * {4 * 6}}
{5 * 24}
120

nn2(5, 1)
nn2(4, 1*5=5)
nn2(3, 4*5=20)
nn2(2, 3*20=60)
nn2(1, 2*60=120)
120

不算,直到遞歸到一個肯定的值後,又從這個具體值向後計算;更耗資源,每次重複的調用都使得調用鏈條不斷加長. 系統使用棧進行數據保存和恢復

每遞歸一次就算出相應的結果。

不能優化成循環

能夠優化成循環

相關文章
相關標籤/搜索