2015年2月14日

前一篇文章讨论了Fibonacci的3种实现方式。本文对Fibonacci 3种实现方式的性能进行了测试。

本次实验是使用3种实现方式来求出Fibonacci的第n个值,观察他们的执行时间来分析其执行效率。

方式参数 n 的值执行时间
递归4825380ms
循环480ms
stack480ms
递归100时间过长,>60s
循环1000ms
stack1000ms
递归100 0000时间过长,>60s
循环100 00004ms
stack100 0000114ms

由测试结果可以看出,递归算法的时间效率远远低于非递归算法。那么时间去哪了呢?

笔者又做了一组测试,观察递归算法来实现Fibonacci的第n个数的值时递归方法调用的次数,和递归算法实现阶乘Factorial的第n个数值时方法调用的次数。

 参数n的值方法调用的次数F(n)的值
阶乘336
Fibonacci331
阶乘55120
Fibonacci593
阶乘10103628800
Fibonacci1010934

由上述的测试结果可看出,同样是求第n个数的值,Fibonacci的调用方法的次数明显多于n的阶乘的次数,增长趋势要增长的更加明显。导致这样的原因是什么呢?

分析一下源码的实现。

Fibonacci  的实现:

public int Fib_Recursion(int n){
		/*System.out.println("----------"+n);*/
		count_Fib++;
		if(n<=0)
			return 0;
		if(n==1){
			return 0;
		}
		if(n==2){
			return 1;
		}
		return Fib_Recursion(n-1)+Fib_Recursion(n-2);
	}

阶乘的实现:

public int factorial(int n){
		count_factorial++;
		if(n==1){
			return 1;
		}
		return n*factorial(n-1);
	}

通过源码可以看出,Fibonacci的源码中调用方法逻辑为 Fib_Recursion(n-1)+Fib_Recursion(n-2) 正式因为这个逻辑,使得当求第n个值的时候,调用了两次自身的方法。

而阶乘的递归调用逻辑为n*factorial(n-1) ,也就是说当求第n个值的时候,调用了一次自身的方法。所以随着n的增加。阶乘递归调用方法的次数是线性的,也就是说方法的调用次数跟跟n的关系为O(n), Fibonacci方法调用的次数跟n的关系是什么样的呢?2的0次方+2的1次方+...2的n-1次方,这样的一个数量级。按照等比数列求和,调用次数的数量级约为O(2的n-2次方)。所以这就是为什么Fibonacci的效率如此之低。

本文所用的测试源码:

package com.pip.structure;

import java.util.Stack;

public class Fibonacci {

	public int count_Fib=0;
	public int count_factorial=0;
	
	public static Fibonacci getInstance(){
		return new Fibonacci();
	}
	
	public int Fib(int n){
		Stack<Integer> s=new Stack<Integer>();
		int top=0;
		if(n==0)
			return 0;
		while(top<=n){
			if(top==0){
				s.push(0);
				top++;
				continue;				
			}
			if(top==1){
				s.push(1);
				top++;
				continue;
			}
			s.push(s.get(top-1)+s.get(top-2));
			top++;
			continue;
		}
		
		return s.peek();
	}
	
	public int Fib_nonRecursion(int n){
		int pre_1=0,pre_2=0,temp;
		for(int i=1;i<=n;i++){
			if(i==1){
				pre_2=0;
			}
			if(i==2){
				pre_1=0;
				pre_2=1;
			}
			
			temp=pre_2;
			pre_2=pre_1+pre_2;
			pre_1=temp;
		}
		return pre_2;
	}
	
	public int Fib_Recursion(int n){
		/*System.out.println("----------"+n);*/
		count_Fib++;
		if(n<=0)
			return 0;
		if(n==1){
			return 0;
		}
		if(n==2){
			return 1;
		}
		return Fib_Recursion(n-1)+Fib_Recursion(n-2);
	}
	

	public int factorial(int n){
		count_factorial++;
		if(n==1){
			return 1;
		}
		return n*factorial(n-1);
	}
	
}

package com.pip.structure;

import java.util.Date;

import org.junit.Test;

public class TestFib {

	@Test
	public void compareFibRecursion() {
		// test recursion
		Fibonacci f=Fibonacci.getInstance();
		long beforeTime = new Date().getTime();
		f.Fib_Recursion(48);
		long afterTime = new Date().getTime();
		System.out.println("recursion-time--" + (afterTime - beforeTime) + "ms");
		
		// test non recursion
		long beforeTime_non = new Date().getTime();
		Fibonacci.getInstance().Fib_nonRecursion(48);
		long afterTime_non = new Date().getTime();
		System.out.println("non_recursion-time--"+ (afterTime_non - beforeTime_non) + "ms");

		// test stack
		long beforeTime_stack = new Date().getTime();
		Fibonacci.getInstance().Fib(48);
		long afterTime_stack = new Date().getTime();
		System.out.println("stack-time--"+ (afterTime_stack - beforeTime_stack) + "ms");
	}

	@Test
	public void compareFibRecursion_100() {
		// test recursion
		Fibonacci f=Fibonacci.getInstance();
		long beforeTime = new Date().getTime();
		f.Fib_Recursion(100);
		long afterTime = new Date().getTime();
		System.out.println("recursion-time--" + (afterTime - beforeTime) + "ms");
		
		// test non recursion
		long beforeTime_non = new Date().getTime();
		Fibonacci.getInstance().Fib_nonRecursion(100);
		long afterTime_non = new Date().getTime();
		System.out.println("non_recursion-time--"+ (afterTime_non - beforeTime_non) + "ms");

		// test stack
		long beforeTime_stack = new Date().getTime();
		Fibonacci.getInstance().Fib(100);
		long afterTime_stack = new Date().getTime();
		System.out.println("stack-time--"+ (afterTime_stack - beforeTime_stack) + "ms");
	}
	
	@Test
	public void compareFibRecursion_10000() {
		// test recursion
		Fibonacci f=Fibonacci.getInstance();
		long beforeTime = new Date().getTime();
		f.Fib_Recursion(10000);
		long afterTime = new Date().getTime();
		System.out.println("recursion-time--" + (afterTime - beforeTime) + "ms");
		
		// test non recursion
		long beforeTime_non = new Date().getTime();
		Fibonacci.getInstance().Fib_nonRecursion(10000);
		long afterTime_non = new Date().getTime();
		System.out.println("non_recursion-time--"+ (afterTime_non - beforeTime_non) + "ms");

		// test stack
		long beforeTime_stack = new Date().getTime();
		Fibonacci.getInstance().Fib(10000);
		long afterTime_stack = new Date().getTime();
		System.out.println("stack-time--"+ (afterTime_stack - beforeTime_stack) + "ms");
	}
	
	@Test
	public void compareFibRecursion_1000000() {
		// test recursion
		Fibonacci f=Fibonacci.getInstance();
		long beforeTime = new Date().getTime();
		f.Fib_Recursion(1000000);
		long afterTime = new Date().getTime();
		System.out.println("recursion-time--" + (afterTime - beforeTime) + "ms");
		
		// test non recursion
		long beforeTime_non = new Date().getTime();
		Fibonacci.getInstance().Fib_nonRecursion(1000000);
		long afterTime_non = new Date().getTime();
		System.out.println("non_recursion-time--"+ (afterTime_non - beforeTime_non) + "ms");

		// test stack
		long beforeTime_stack = new Date().getTime();
		Fibonacci.getInstance().Fib(1000000);
		long afterTime_stack = new Date().getTime();
		System.out.println("stack-time--"+ (afterTime_stack - beforeTime_stack) + "ms");
	}
	
	@Test
		public void compareFibAndFac() {
			Fibonacci f = Fibonacci.getInstance();
			System.out.println("Factorial value-----" +f.factorial(3));
			System.out.println("Factorial count-----" + f.count_factorial);
			System.out.println("Fibonacci value-----" + f.Fib_Recursion(3));
			System.out.println("Fibonacci count-----" + f.count_Fib);

			Fibonacci f2 = Fibonacci.getInstance();
			System.out.println("Factorial value-----" + f2.factorial(5));
			System.out.println("Factorial count-----" + f2.count_factorial);
			System.out.println("Fibonacci value-----" +f2.Fib_Recursion(5));
			System.out.println("Fibonacci count-----" + f2.count_Fib);

			Fibonacci f3 = Fibonacci.getInstance();
			System.out.println("Factorial value-----" + f3.factorial(10));
			System.out.println("Factorial count-----" + f3.count_factorial);
			System.out.println("Fibonacci value-----" +f3.Fib_Recursion(10));
			System.out.println("Fibonacci count-----" + f3.count_Fib);
		}

}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值