目录
斐波那契数是什么?
- 斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”
- 斐波那契数列指的是这样一个数列 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项开始,每一项都等于前两项之和。在数学上,斐波纳契数列以如下被以递推的方法定义:
- F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*).
斐波那契相关数学问题:
楼梯问题:
- 有一段楼梯有10级台阶,规定每一步只能跨一级或两级,要登上第10级台阶有几种不同的走法?
- 这就是一个斐波那契数列:登上第一级台阶有一种登法;登上两级台阶,有两种登法;登上三级台阶,有三种登法;登上四级台阶,有五种登法……
- 1,2,3,5,8,13……所以,登上十级,有89种走法。
硬币问题:
- 一枚均匀的硬币掷10次,问不连续出现正面的可能情形有多少种?
- 答案是(1/√5)*{[(1+√5)/2]^(10+2) - [(1-√5)/2]^(10+2)}=144种。
- 求递推数列a⑴=1,a(n+1)=1+1/a(n)的通项公式
- 由数学归纳法可以得到:a(n)=F(n+1)/F(n),将斐波那契数列的通项式代入,化简就得结果。
兔子繁殖问题
- 斐波那契数列又因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”。
- 一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?
- 我们不妨拿新出生的一对小兔子分析一下:
- 第一个月小兔子没有繁殖能力,所以还是一对
- 两个月后,生下一对小兔对数共有两对
- 三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对;
- 依次类推可以列出下表:
经过月数 | 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 |
- 幼仔对数=前月成兔对数
- 成兔对数=前月成兔对数+前月幼仔对数
- 总体对数=本月成兔对数+本月幼仔对数
- 可以看出幼仔对数、成兔对数、总体对数都构成了一个数列。这个数列有关十分明显的特点,那是:前面相邻两项之和,构成了后一项。
运用递归函数求第n个斐波那契数:
递归详解:
递归是什么?
- 程序调用自身的编程技巧称为递归,是函数自己调用自己。
- 使用递归要注意的有两点:
- 递归就是在过程或函数里面调用自身;
- 在使用递归时, 必须有一个明确的递归结束条件, 称为递归出口.
递归原理:
- 递归分为两个阶段:
- 递推:把复杂的问题的求解推到比原问题简单一些的问题的求解;
- 回归:当获得最简单的情况后, 逐步返回, 依次得到复杂的解
- .优点:
- 代码更简洁清晰,可读性更好递归可读性好这一点,对于初学者可能会反对。
- 实际上递归的代码更清晰,但是从学习的角度要理解递归真正发生的什么,是如何调用的,调用层次和路线,调用堆栈中保存了什么,可能是不容易。
- 但是不可否认递归的代码更简洁
- 缺点:
- 由于递归需要系统堆栈,所以空间消耗要比非递归代码要大很多。
- 而且,如果递归深度太大,可能会造成栈溢出
-
代码示例:
#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 - 优点:
- 迭代效率高,运行时间只因循环次数增加而增加;
- 没什么额外开销,空间上也没有什么增加;
- 缺点:
- 不容易理解;
- 代码不如递归简洁
- 编写复杂问题时困难。
- 注意:
- 能用迭代的不用递归,递归调用函数,浪费空间,
- 并且递归太深容易造成堆栈的溢出
-
代码示例:
-
#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; }
运行结果: