斐波那契數列:0、1、1、2、3、5、8、13…………
他的規律是,第一項是0,第二項是1,第三項開始(含第三項)等於前兩項之和。
> 遞歸實現
看到這個規則,第一個想起當然是遞歸算法去實現了,於是寫了以下一段:
public class RecursionForFibonacciSequence { public static void main(String[] args) { System.out.println(recursion(10)); } public static double recursion(double i) { if (i == 0) { printResult(i, 0); return 0; } if (i == 1) { printResult(i, 1); return 1; } double result = recursion(i - 1) + recursion(i - 2); printResult(i, result); return result; } /** * 打印結果 */ public static void printResult(double i, double result) { System.out.println(i + " -> " + result); } }
它能正常運行,比如計算第10項的結果為55。
但是,計算數字大點的數據,則很慢很慢,因為重復計算太多了。
日志:

1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 4.0 -> 3.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 5.0 -> 5.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 4.0 -> 3.0 6.0 -> 8.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 4.0 -> 3.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 5.0 -> 5.0 7.0 -> 13.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 4.0 -> 3.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 5.0 -> 5.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 4.0 -> 3.0 6.0 -> 8.0 8.0 -> 21.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 4.0 -> 3.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 5.0 -> 5.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 4.0 -> 3.0 6.0 -> 8.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 4.0 -> 3.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 5.0 -> 5.0 7.0 -> 13.0 9.0 -> 34.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 4.0 -> 3.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 5.0 -> 5.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 4.0 -> 3.0 6.0 -> 8.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 4.0 -> 3.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 5.0 -> 5.0 7.0 -> 13.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 4.0 -> 3.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 5.0 -> 5.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 4.0 -> 3.0 6.0 -> 8.0 8.0 -> 21.0 10.0 -> 55.0 55.0
> 遞歸值緩存實現
用最直觀的方式優化,既然重復計算太多了,而重復計算的結果都是一樣的,那么我們就將重復計算的結果集緩存起來吧。
因為上例的遞歸效率低,不能執行太多的項數,所以只執行到10,而下面這個寫法的效率大為提高,所以我們執行到100看看。
import java.util.HashMap; import java.util.Map; public class CacheForFibonacciSequence { public static void main(String[] args) { System.out.println(recursion(100)); } // 緩存計算結果集 public static Map<Double, Double> map = new HashMap<Double, Double>(); public static double recursion(double i) { if (i == 0) { printResult(i, 0); return 0; } if (i == 1) { printResult(i, 1); return 1; } if (map.containsKey(i)) { return map.get(i); } double result = recursion(i - 1) + recursion(i - 2); printResult(i, result); map.put(i, result); return result; } /** * 打印結果 */ public static void printResult(double i, double result) { System.out.println(i + " -> " + result); } }
日志:

1.0 -> 1.0 0.0 -> 0.0 2.0 -> 1.0 1.0 -> 1.0 3.0 -> 2.0 4.0 -> 3.0 5.0 -> 5.0 6.0 -> 8.0 7.0 -> 13.0 8.0 -> 21.0 9.0 -> 34.0 10.0 -> 55.0 11.0 -> 89.0 12.0 -> 144.0 13.0 -> 233.0 14.0 -> 377.0 15.0 -> 610.0 16.0 -> 987.0 17.0 -> 1597.0 18.0 -> 2584.0 19.0 -> 4181.0 20.0 -> 6765.0 21.0 -> 10946.0 22.0 -> 17711.0 23.0 -> 28657.0 24.0 -> 46368.0 25.0 -> 75025.0 26.0 -> 121393.0 27.0 -> 196418.0 28.0 -> 317811.0 29.0 -> 514229.0 30.0 -> 832040.0 31.0 -> 1346269.0 32.0 -> 2178309.0 33.0 -> 3524578.0 34.0 -> 5702887.0 35.0 -> 9227465.0 36.0 -> 1.4930352E7 37.0 -> 2.4157817E7 38.0 -> 3.9088169E7 39.0 -> 6.3245986E7 40.0 -> 1.02334155E8 41.0 -> 1.65580141E8 42.0 -> 2.67914296E8 43.0 -> 4.33494437E8 44.0 -> 7.01408733E8 45.0 -> 1.13490317E9 46.0 -> 1.836311903E9 47.0 -> 2.971215073E9 48.0 -> 4.807526976E9 49.0 -> 7.778742049E9 50.0 -> 1.2586269025E10 51.0 -> 2.0365011074E10 52.0 -> 3.2951280099E10 53.0 -> 5.3316291173E10 54.0 -> 8.6267571272E10 55.0 -> 1.39583862445E11 56.0 -> 2.25851433717E11 57.0 -> 3.65435296162E11 58.0 -> 5.91286729879E11 59.0 -> 9.56722026041E11 60.0 -> 1.54800875592E12 61.0 -> 2.504730781961E12 62.0 -> 4.052739537881E12 63.0 -> 6.557470319842E12 64.0 -> 1.0610209857723E13 65.0 -> 1.7167680177565E13 66.0 -> 2.7777890035288E13 67.0 -> 4.4945570212853E13 68.0 -> 7.2723460248141E13 69.0 -> 1.17669030460994E14 70.0 -> 1.90392490709135E14 71.0 -> 3.08061521170129E14 72.0 -> 4.98454011879264E14 73.0 -> 8.06515533049393E14 74.0 -> 1.304969544928657E15 75.0 -> 2.11148507797805E15 76.0 -> 3.416454622906707E15 77.0 -> 5.527939700884757E15 78.0 -> 8.944394323791464E15 79.0 -> 1.447233402467622E16 80.0 -> 2.3416728348467684E16 81.0 -> 3.7889062373143904E16 82.0 -> 6.1305790721611584E16 83.0 -> 9.9194853094755488E16 84.0 -> 1.60500643816367072E17 85.0 -> 2.5969549691112256E17 86.0 -> 4.2019614072748966E17 87.0 -> 6.7989163763861222E17 88.0 -> 1.10008777836610189E18 89.0 -> 1.77997941600471398E18 90.0 -> 2.880067194370816E18 91.0 -> 4.6600466103755305E18 92.0 -> 7.5401138047463465E18 93.0 -> 1.2200160415121877E19 94.0 -> 1.9740274219868226E19 95.0 -> 3.19404346349901E19 96.0 -> 5.168070885485833E19 97.0 -> 8.362114348984843E19 98.0 -> 1.3530185234470676E20 99.0 -> 2.189229958345552E20 100.0 -> 3.54224848179262E20 3.54224848179262E20
> 循環方式
還有我們也可以用循環的方式,只用兩個變量緩存前兩項的值:
public class ForeachForFibonacciSequence { public static void main(String[] args) { System.out.println(foreach(100)); } public static double foreach(double i) { if (i <= 0d) { return 0d; } if (i == 1d) { return 1d; } double temp1 = 0d; double temp2 = 1d; double tempSum = 0; for (double d = 2; d <= i; d++) { tempSum = temp1 + temp2; printResult(d, tempSum); temp1 = temp2; temp2 = tempSum; } return tempSum; } /** * 打印結果 */ public static void printResult(double i, double result) { System.out.println(i + " -> " + result); } }
日志:

2.0 -> 1.0 3.0 -> 2.0 4.0 -> 3.0 5.0 -> 5.0 6.0 -> 8.0 7.0 -> 13.0 8.0 -> 21.0 9.0 -> 34.0 10.0 -> 55.0 11.0 -> 89.0 12.0 -> 144.0 13.0 -> 233.0 14.0 -> 377.0 15.0 -> 610.0 16.0 -> 987.0 17.0 -> 1597.0 18.0 -> 2584.0 19.0 -> 4181.0 20.0 -> 6765.0 21.0 -> 10946.0 22.0 -> 17711.0 23.0 -> 28657.0 24.0 -> 46368.0 25.0 -> 75025.0 26.0 -> 121393.0 27.0 -> 196418.0 28.0 -> 317811.0 29.0 -> 514229.0 30.0 -> 832040.0 31.0 -> 1346269.0 32.0 -> 2178309.0 33.0 -> 3524578.0 34.0 -> 5702887.0 35.0 -> 9227465.0 36.0 -> 1.4930352E7 37.0 -> 2.4157817E7 38.0 -> 3.9088169E7 39.0 -> 6.3245986E7 40.0 -> 1.02334155E8 41.0 -> 1.65580141E8 42.0 -> 2.67914296E8 43.0 -> 4.33494437E8 44.0 -> 7.01408733E8 45.0 -> 1.13490317E9 46.0 -> 1.836311903E9 47.0 -> 2.971215073E9 48.0 -> 4.807526976E9 49.0 -> 7.778742049E9 50.0 -> 1.2586269025E10 51.0 -> 2.0365011074E10 52.0 -> 3.2951280099E10 53.0 -> 5.3316291173E10 54.0 -> 8.6267571272E10 55.0 -> 1.39583862445E11 56.0 -> 2.25851433717E11 57.0 -> 3.65435296162E11 58.0 -> 5.91286729879E11 59.0 -> 9.56722026041E11 60.0 -> 1.54800875592E12 61.0 -> 2.504730781961E12 62.0 -> 4.052739537881E12 63.0 -> 6.557470319842E12 64.0 -> 1.0610209857723E13 65.0 -> 1.7167680177565E13 66.0 -> 2.7777890035288E13 67.0 -> 4.4945570212853E13 68.0 -> 7.2723460248141E13 69.0 -> 1.17669030460994E14 70.0 -> 1.90392490709135E14 71.0 -> 3.08061521170129E14 72.0 -> 4.98454011879264E14 73.0 -> 8.06515533049393E14 74.0 -> 1.304969544928657E15 75.0 -> 2.11148507797805E15 76.0 -> 3.416454622906707E15 77.0 -> 5.527939700884757E15 78.0 -> 8.944394323791464E15 79.0 -> 1.447233402467622E16 80.0 -> 2.3416728348467684E16 81.0 -> 3.7889062373143904E16 82.0 -> 6.1305790721611584E16 83.0 -> 9.9194853094755488E16 84.0 -> 1.60500643816367072E17 85.0 -> 2.5969549691112256E17 86.0 -> 4.2019614072748966E17 87.0 -> 6.7989163763861222E17 88.0 -> 1.10008777836610189E18 89.0 -> 1.77997941600471398E18 90.0 -> 2.880067194370816E18 91.0 -> 4.6600466103755305E18 92.0 -> 7.5401138047463465E18 93.0 -> 1.2200160415121877E19 94.0 -> 1.9740274219868226E19 95.0 -> 3.19404346349901E19 96.0 -> 5.168070885485833E19 97.0 -> 8.362114348984843E19 98.0 -> 1.3530185234470676E20 99.0 -> 2.189229958345552E20 100.0 -> 3.54224848179262E20 3.54224848179262E20
> 尾遞歸方式
從回復的網友“Mr_listening”的博文中了解到,還可以用尾遞歸的方式實現,看以下代碼:
public class RecursionTailForFibonacciSequence { public static void main(String[] args) { System.out.println(recursionTail(10, 1, 1)); } public static double recursionTail(int i, double temp1, double temp2) { if (i < 2) { return temp1; } double result = recursionTail(i - 1, temp2, temp1 + temp2); printResult(i - 1, temp2, temp1 + temp2, result); return result; } /** * 打印結果 */ public static void printResult(double i, double temp1, double temp2, double result) { System.out.println("recursionTail(" + i + ", " + temp1 + ", " + temp2 + ") -> " + result); } }
日志:

recursionTail(1.0, 55.0, 89.0) -> 55.0 recursionTail(2.0, 34.0, 55.0) -> 55.0 recursionTail(3.0, 21.0, 34.0) -> 55.0 recursionTail(4.0, 13.0, 21.0) -> 55.0 recursionTail(5.0, 8.0, 13.0) -> 55.0 recursionTail(6.0, 5.0, 8.0) -> 55.0 recursionTail(7.0, 3.0, 5.0) -> 55.0 recursionTail(8.0, 2.0, 3.0) -> 55.0 recursionTail(9.0, 1.0, 2.0) -> 55.0 55.0