浅谈递归与尾递归
? ? ? 一個對自己本身的遞歸尾調用,就叫做尾遞歸。這里尾調用的“尾”字,是指運行時需要執行的最后一個動作。不是簡單的語法字面上的最后一個語句。 尾遞歸實際執行的是迭代的計算過程。線性遞歸函數必須滿足以下兩個基本屬性:
? ? ?*必須清晰無誤地解決基的情況。
? ? ?*每一個遞歸的調用,必須包含更小的參數值。
? ? ? 而尾遞歸則不必滿足這兩個條件。
? ? ? 普通的線性遞歸比尾遞歸更加消耗資源, 在實現上說, 每次重復的過程調用都使得調用鏈條不斷加長. 系統不得不使用棧進行數據保存和恢復.而尾遞歸就不存在這樣的問題, 因為它的狀態完全由函數的參數保存. 并且,由于尾遞歸的函數調用出現在調用者函數的尾部,因為是尾部,所以根本沒有必要去保存任何局部變量。直接讓被調用的函數返回時越過調用者,返回到調用者的調用者去。尾調用優化不是什么很復雜的優化,實際上幾乎所有的現代的高級語言編譯器都支持尾調用這個很基本的優化。 實現層面上,只需要把匯編代碼call改成jmp, 并放棄所有局部變量壓棧處理,就可以了。這樣一來,堆棧根本就沒有被占用,每次調用都是重新使用調用者的堆棧。盡管尾遞歸比遞歸高效,但并非所有的遞歸算法都可以轉成尾遞歸的,因為尾遞歸本質上執行的是迭代的計算過程。這與并非所有的遞歸算法都可以轉成迭代算法的原因是一樣的。
? ? ? 例子:java實現
public class Recursion {
public static void main(String[] args) {
System.out.println(factorial(6));
System.out.println(factorial2(6, 1));
System.out.println(reciprocal(3.0));
System.out.println(reciprocal2(3.0, 1));
}
// 遞歸 求 N 的階乘
private static int factorial(int n) {
if (n == 0 || n == 1) {
return 1;
} else if (n < 0) {
return 0;
} else {
return n * factorial(n - 1);
}
}
// 尾遞歸 求 N 的階乘
private static int factorial2(int n, int result) {
if (n == 0 || n == 1) {
return result;
} else if (n < 0) {
return 0;
} else {
return factorial2(n - 1, result * n);
}
}
// 遞歸求 1+1/2+1/3+1/4+......+n/1
private static double reciprocal(double n) {
if (n < 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
return 1.0 / n + reciprocal(n - 1);
}
}
// 尾遞歸 求 1+1/2+1/3+1/4+......+1/n
private static double reciprocal2(double n, double result) {
if (n < 0) {
return 0;
} else if (n == 1) {
return result;
} else {
return reciprocal2(n - 1, result + 1.0 / n);
}
}
}
轉載于:https://www.cnblogs.com/lsc183/archive/2012/12/24/weidigui.html
總結
- 上一篇: js树形导航栏 jquery
- 下一篇: 求数组中的最长递增子序列