• 【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
  • 相关阅读:
    第十一周项目6-回文&素数(一)
    第十一周项目1-函数版星号图(三) .
    囚徒困境 For BBasic
    第十一周项目5-当年第几天
    第十一周项目4-特殊三位数
    第十一周项目3-程序的多文件组织
    第十一周项目2-求最大公约数
    第十一周项目1-函数版星号图(二)
    第十一周项目1-函数版星号图(一)
    第十周-囚徒困境
  • 原文地址:https://www.cnblogs.com/nick-huang/p/5222834.html
Copyright © 2020-2023  润新知