斐波那契数列的三种实现方式

斐波那契数列的实现是一道很经典的笔试题,大家都知道可以用递归轻松地解决。


今天我主要是写一种一样是递归,但是我在网上没看到过的实现方式。我的这种实现方式应该算是尾递归吧

尾递归:如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。当递归调用是整个函数体中最后执行的语句

且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。尾递归函数的特点是在回归过程中不用做任何操作


记得把数据类型改为 long,如果数据类型是 int,算第 47 项就出错了。

package penTest;
//斐波那契数列

public class Fibonacci_recursion {
	public static void main(String[] args) {
		long start1 = System.currentTimeMillis();
		long num1 = fibonaciiNormal(40);
		long end1 = System.currentTimeMillis();
		
		long start2 = System.currentTimeMillis();
		long num2 = fibonaciiTailRecursion(1, 1, 40);
		long end2 = System.currentTimeMillis();
		
		long start3 = System.currentTimeMillis();
		long num3 = fibonaciiRecursion(40);
		long end3 = System.currentTimeMillis();
		
		System.out.println("普通迭代:" + num1);
		System.out.println("用时:" + (end1 - start1));
		System.out.println("尾  递  归:" + num2);
		System.out.println("用时:" + (end2 - start2));
		System.out.println("递        归:" + num3);
		System.out.println("用时:" + (end3 - start3));
	}

				//方式一
	private static long fibonaciiRecursion(long n) {
		if(n == 1 || n == 2)
			return 1;
		return fibonaciiRecursion(n - 1) + fibonaciiRecursion(n - 2);
	}

				//方式二
	private static long fibonaciiTailRecursion(long former, long latter, long n) {
		if(n == 1 || n == 2)
			return 1;
		
		long temp = former;
		former = latter;
		latter = temp + latter;
		
		return temp + fibonaciiTailRecursion(former, latter, n - 1);
	}
	
			//方式三
	private static long fibonaciiNormal(long n) {
		long sum = 0;
		long latter = 1;
		long former = 1;
		
		if(n > 2) {
			for(long i = 3; i < n; i++) {
				sum = former + latter;
				former = latter;
				latter = sum;
			}
			sum = former + latter;
		}
		
		if(n == 1 || n == 2)
			sum = 1;
		return sum;
	}
}

网上看到都绝大多数是方式一实现的,代码非常简单,我把这种方式看成两个递归,执行起来效率很比较低,因此就想用一个递归实现

方式二是我自己想出来的,在网上似乎还没看到别人写过。这种方式只有一个递归,而且回归的时候不用操作,效率会比方式一高一点

效率测试如下图:

斐波那契数列的三种实现方式_第1张图片 斐波那契数列的三种实现方式_第2张图片

斐波那契数列的三种实现方式_第3张图片  斐波那契数列的三种实现方式_第4张图片

斐波那契数列的三种实现方式_第5张图片


1、n 为 40 时,递归方式就明显比其他两种方式慢了

2、n 为 5000 时,结果正常;

      n 为 6000 时,结果出现负数,说明结果的范围已经超出数据类型的长度;(每次测试 +1000)

      n 为 8000 时,出现栈溢出。发现出现栈溢出的只是 尾递归

3、迭代和尾递归两种方式的执行时间一直都是 0,突然感觉两种方式特别类似,不过尾递归方式没有循环,用的是递归

综上:迭代方法效率高,占空间小,只是代码量稍多了些

            尾递归比普通递归好一些



你可能感兴趣的:(Java)