遞歸: 函數
例子4:上臺階 優化
上N級臺階,便可每次1步也可每次2步走,共有多少種不一樣走法 spa
解法:邁出第一步有兩種方法,第一步後就是N-1和N-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) |
nn2(5, 1) |
不算,直到遞歸到一個肯定的值後,又從這個具體值向後計算;更耗資源,每次重複的調用都使得調用鏈條不斷加長. 系統使用棧進行數據保存和恢復 |
每遞歸一次就算出相應的結果。 |
不能優化成循環 |
能夠優化成循環 |