斐波拉契数列的递归实现和非递归实现及其时间复杂度分析

斐波拉契数列的实现和时间复杂度的分析算是一个难点,在考研数据结构中也经常会碰到,今天我们就来仔细分析下和解决掉这个问题。

1. 首先,我们先来看看递归形式斐波拉契数列的C语言实现:

# include<stdio.h>
 
int main(){
    
    
	printf("%d",Fibonacci(5));
}

int Fibonacci(int n){
    
    
	if(n==1 || n==2)
	   return 1;
	else{
    
    
	  return Fibonacci(n-1)+Fibonacci(n-2);	
	}
} 

值得注意的是,判断语句为什么要这么写,首先我们要明确递归肯定是要有出口的,不然就会无限开辟空间–直接爆炸!!,那么这里的出口为什么是判断n=1或者n=2呢,是因为斐波拉契数列的特殊性质所决定

第一个是斐波拉契数列的前几项分别是0 1 1 2 这样的,所以在编程的时候我们根据数组的设计模式,设计第0项为0,从第一项开始为1。
第二个是斐波拉契数列是需要前两项相加的,而f(1)=f(0)+f(-1),这肯定是不行的对吧,f(2)=f(1)+f(0),f(0)是没有被定义的,所有我们需要手动返回1,这就是判断语句这样设置的由来。当然其实我个人认为,也许这样定义斐波拉契函数会更加易懂:

# include<stdio.h>
 
int main(){
    
    
	printf("%d",Fibonacci(0));
}

int Fibonacci(int n){
    
     
    if(n==0){
    
    
    	return 0;
	}
	if(n==1 || n==2)
	   return 1;
	else{
    
    
	  return Fibonacci(n-1)+Fibonacci(n-2);	
	}
} 


2. 时间复杂度分析:

先看看一般递归法的时间复杂度分析模式:
递归函数的时间复杂度分析一般是采用递推法来实现。
例如求阶乘的算法的时间复杂度分析:

int fac(int n)/*递归函数*/
{
    
    
    if (n < 0)
        printf("n<0,data error!");
    else
        if (n == 0 || n == 1)
            return 1;
        else
            return  f(n - 1) * n;
}

在这里插入图片描述
这就是递归分析法,注意上面我们假定 1为 执行了一次函数调用语句,这种方法常用于分析递归算法,记住它的使用很重要
好了,现在我们同样使用这种方法来分析斐波拉契实现算法的时间复杂度:
在这里插入图片描述

可以看到,我们初步的分析出了其时间复杂度为O(2^n),可以说明其确实时间复杂度是成指数倍增长的,所以我们还是要尽量少使用它。
所以总结一下,对于递归算法的时间复杂度分析,关键是在于分析调用函数次数和具体执行次数的关系,网上还有另外一种用二叉树的分析方法,大家可自行查阅,我就不再重复了。
对于斐波拉契算法的非递归实现的时间复杂度分析,其较为简单为O(n),这里就不再赘述了。

int non_recursive_method(int n)
{
    
    
int p = 1;
int q = 1;
if (n == 1 || n == 2)
return 1;
else
{
    
    
for(int i = 3; i < n; i++)
{
    
    
int tmp = p;//将第一个值p赋给tmp
p = q;       //将第二个值q赋给p,以后每一次赋值都将得到的最新的F(n)赋给p,从后面语句可//以看出,q储存的为最新的F(n)
 
q = tmp + q;
}
return q;
}

猜你喜欢

转载自blog.csdn.net/weixin_45870904/article/details/111186846