zoukankan      html  css  js  c++  java
  • 【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
  • 相关阅读:
    uva 147 Dollars
    hdu 2069 Coin Change(完全背包)
    hdu 1708 Fibonacci String
    hdu 1568 Fibonacci
    hdu 1316 How Many Fibs?
    poj 1958 Strange Towers of Hanoi
    poj 3601Tower of Hanoi
    poj 3572 Hanoi Tower
    poj 1920 Towers of Hanoi
    筛选法——素数打表
  • 原文地址:https://www.cnblogs.com/nick-huang/p/5222834.html
Copyright © 2011-2022 走看看