【Java】斐波那契數列(Fibonacci Sequence、兔子數列)的3種計算方法(遞歸實現、遞歸值緩存實現、循環實現、尾遞歸實現)


斐波那契數列: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
View Code

 

> 遞歸值緩存實現

用最直觀的方式優化,既然重復計算太多了,而重復計算的結果都是一樣的,那么我們就將重復計算的結果集緩存起來吧。

因為上例的遞歸效率低,不能執行太多的項數,所以只執行到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
View Code

 

 

> 循環方式

還有我們也可以用循環的方式,只用兩個變量緩存前兩項的值:

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
View Code

 

> 尾遞歸方式

從回復的網友“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
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM