【C语言-31】如何用递归和非递归分别实现求第n个斐波那契数?

目录

斐波那契数是什么?

斐波那契相关数学问题:

楼梯问题:

硬币问题:

兔子繁殖问题

运用递归函数求第n个斐波那契数:

递归详解:

代码示例:

运用非递归求第n个斐波那契数:

迭代简解:

代码示例:


斐波那契数是什么?

  1. 斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列
  2. 斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368........
  3. 这个数列从第3项开始,每一项都等于前两项之和。在数学上,斐波纳契数列以如下被以递推的方法定义:                                      
  4. F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*).

斐波那契相关数学问题:

楼梯问题:

  1. 有一段楼梯有10级台阶,规定每一步只能跨一级或两级,要登上第10级台阶有几种不同的走法?
  2. 这就是一个斐波那契数列:登上第一级台阶有一种登法;登上两级台阶,有两种登法;登上三级台阶,有三种登法;登上四级台阶,有五种登法……
  3. 1,2,3,5,8,13……所以,登上十级,有89种走法。

硬币问题:

  1. 一枚均匀的硬币掷10次,问不连续出现正面的可能情形有多少种?
  2. 答案是(1/√5)*{[(1+√5)/2]^(10+2) - [(1-√5)/2]^(10+2)}=144种。
  3. 求递推数列a⑴=1,a(n+1)=1+1/a(n)的通项公式
  4. 数学归纳法可以得到:a(n)=F(n+1)/F(n),将斐波那契数列的通项式代入,化简就得结果。

兔子繁殖问题

  1. 斐波那契数列又因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”。
  2. 一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?
  3. 我们不妨拿新出生的一对小兔子分析一下:
  4. 第一个月小兔子没有繁殖能力,所以还是一对
  5. 两个月后,生下一对小兔对数共有两对
  6. 三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对;
  7. 依次类推可以列出下表:

经过月数

1

2

3

4

5

6

7

8

9

10

11

12

幼仔对数

1

0

1

1

2

3

5

8

13

21

34

55

成兔对数

0

1

1

2

3

5

8

13

21

34

55

89

 

总体对数

1

1

2

3

5

8

13

21

34

55

89

144

 
  1. 幼仔对数=前月成兔对数
  2. 成兔对数=前月成兔对数+前月幼仔对数
  3. 总体对数=本月成兔对数+本月幼仔对数
  4. 可以看出幼仔对数、成兔对数、总体对数都构成了一个数列。这个数列有关十分明显的特点,那是:前面相邻两项之和,构成了后一项。

运用递归函数求第n个斐波那契数:

递归详解:

递归是什么?

  1. 程序调用自身的编程技巧称为递归,是函数自己调用自己。
  2. 使用递归要注意的有两点:
  • 递归就是在过程或函数里面调用自身;
  • 在使用递归时, 必须有一个明确的递归结束条件, 称为递归出口.

递归原理:

  1. 递归分为两个阶段:
  • 递推:把复杂的问题的求解推到比原问题简单一些的问题的求解;
  • 回归:当获得最简单的情况后, 逐步返回, 依次得到复杂的解
  •  
  • .优点:
  • 代码更简洁清晰,可读性更好递归可读性好这一点,对于初学者可能会反对。
  • 实际上递归的代码更清晰,但是从学习的角度要理解递归真正发生的什么,是如何调用的,调用层次和路线,调用堆栈中保存了什么,可能是不容易。
  •  
  • 但是不可否认递归的代码更简洁
  • 缺点:
  • 由于递归需要系统堆栈,所以空间消耗要比非递归代码要大很多。
  • 而且,如果递归深度太大,可能会造成栈溢出
  1. 代码示例:

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>

#include<stdlib.h>

int fib(int n)
{
	if (n <= 2)
	{
		return 1;
	}
	else
		return fib(n - 1) + fib(n - 2);  //所求的数是它前两个数之和
}
int main()
{
	int n = 0;

	printf("求第n个斐波那契数:");

	scanf("%d", &n);

	printf("第%d个斐波那契数是%d\n", n,fib(n));

	system("pause");
	return 0;
}


运行结果:

运用非递归求第n个斐波那契数:

  • 迭代简解:


  • 1、利用变量的原值推算出变量的一个新值.如果递归是自己调用自己的话,迭代就是A不停的调用B                                             

  • 优点:
  1. 迭代效率高,运行时间只因循环次数增加而增加;
  2. 没什么额外开销,空间上也没有什么增加;
  • 缺点:
  1. 不容易理解;  
  2.   代码不如递归简洁
  3. 编写复杂问题时困难。
  • 注意:
  1. 能用迭代的不用递归,递归调用函数,浪费空间,
  2. 并且递归太深容易造成堆栈的溢出
  3.  
  4. 代码示例:

  5. #define _CRT_SECURE_NO_WARNINGS
    
    #include <stdio.h>
    
    #include <stdlib.h>
    int main()
    
    {
    	int n = 0;
    	int a = 1;
    	int b = 1;
    	int c = 0;
    	int i = 0;
    
    	printf("输入你想求第几个斐波那契数:\n");
    
    	scanf("%d", &n);
    
    	if (n <= 2) {
    
    		printf("第%d个斐波那契数是%d\n", n,a);
    	}
    	else {
    		for (i = 0; i < n - 2; ++i)
    		{
    			c = a + b;
    			a = b;
    			b = c;
    			
    		}
    
    		printf("第%d个斐波那契数是%d ", n,c);
    	}
    	printf("\n");
    
    	system("pause");
    	return 0;
    }
    

    运行结果:

猜你喜欢

转载自blog.csdn.net/weixin_44749767/article/details/89289230