算法 · 深入理解 Fibonacci 数列计算及黄金分割

本文深入探讨斐波那契数列的四种计算方法,包括二分递归、线性递归、迭代计算和通项公式求解,分析它们的时间复杂度和空间复杂度。此外,文章还介绍了斐波那契数列与黄金分割的关系,以及在UI设计、建筑、自然科学等多个领域的应用。

在自然界中,有一串数字我们时常能看到,它的前几项序列是:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233…

如果用数学语言描述,它的递归形式是这样的:
{ F0=0F1=1Fn=Fn−1+Fn−2(n≥2) \begin{cases} F_0 = 0 \\ F_1 = 1 \\ F_n = F_{n-1}+F_{n-2} &(n\geq2) \end{cases} F0=0F1=1Fn=Fn1+Fn2(n2)

也就是说,除了 第0项第1项,之后的数字是由这个数紧邻的前两个数字,相加得到的。

如果用几何图形表示,你可能见过这张图:

在这里插入图片描述

这就是***斐波那契数***,它形成的数列就被称为***斐波那契数列。***

名称源自1170年出生的意大利比萨数学家***列奥纳多·斐波那契***:Leonardo Fibonacci。

(歪个楼:列奥纳多·迪·塞尔·皮耶罗·达·芬奇,出生于1452年)

求解和利用斐波那契数及数列,是现代计算机科学与传统古典艺术、现代新媒体艺术设计的热门交叉点,包括但不限于图形学、性能优化、先锋艺术、影视创作等等分支领域。

其中最为著名的,就是黄金螺旋分割线。所以此篇追根溯源,深入到算法和数学的最底层面,理解斐波那契数列的计算方式。

① Fibonacci_1(n):定义式二分递归计算

根据上述定义式,fib() 函数的伪代码描述为(默认 n 为非负数):
fib(n)={ n(ifn≤1)fib(n−1)+fib(n−2)(ifn≥2) fib(n)= \begin{cases} n & (if &n\leq1)\\ fib(n-1)+fib(n-2) & (if &n\geq2) \end{cases} fib(n)={ nfib(n1)+fib(n2)(if(ifn1)n2)

// C++
int fib1(int n){
   
   
    return (2 > n) ? n : fib1(n - 1) + fib1(n - 2);
}

显然,这种算法浅显易懂,直接根据定义式编码即可。

但弊端也很显而易见,二分递归的形式,其计算效率非常低下。

假设,计算 fib(n) 所需的时间为 T(n) 。那么根据此算法思路,计算 fib(n-1) 则相应的需要 T(n-1) 的时间,直到最后花费一个单位的时间,将其累加。

故,T(n) 的递推式为:

T(n)={ 1(ifn≤1)T(n−1)+T(n−2)+1(ifn≥2) T(n)= \begin{cases} 1 & (if &n\leq1)\\ T(n-1)+T(n-2) + 1 & (if &n\geq2) \end{cases} T(n)={ 1T(n1)+T(n2)+1(if(ifn1)n2)

仔细观察,就会发现 T(n)fib(n) 长得非常像。

那么,令 S(n) = [T(n)+1]/2

S(n)=[T(n)+1]/2={ (1+1)/2[T(n−1)+T(n−2)+1+1]/2={ (1+1)/2{ [2∗S(n−1)−1]+[2∗S(n−2)−1]+1+1]}/2={ (1+1)/2[2∗S(n−1)+2∗S(n−2)]/2={ 1(ifn≤1)S(n−1)+S(n−2)(ifn≥2) \begin{aligned} S(n)&= [T(n)+1]/2 \\ &= \begin{cases} (1+1)/2 \\ [T(n-1)+T(n-2)+1+1]/2 \\ \end{cases} \\ & = \begin{cases} (1+1)/2 \\ \{[2*S(n-1)-1] + [2*S(n-2)-1] +1 +1 ]\}/2 \end{cases} \\ & = \begin{cases} (1+1)/2 \\ [2*S(n-1) + 2*S(n-2)]/2 \\ \end{cases} \\ &= \begin{cases} 1 & (if &n\leq1)\\ S(n-1)+S(n-2) & (if &n\geq2) \end{cases} \\ \end{aligned} S(n)=[T(n)+1]/2={ (1+1)/2[T(n1)+T(n2)+1+1]/2={ (1+1)/2{ [2S(n1)1]+[2S(n2)1]+1+1]}/2={ (1+1)/2[2S(n1)+2S(n2)]/2={ 1S(n1)+S(n2)(if(ifn1)n2)

由此可以发现,除了起始项目外,S(n)fib(n) 在形式上一致。

而且:
{ S(0)=(T(0)+1)/2=1=fib(1)S(1)=(T(1)+1)/2=1=fib(2) \begin{cases} S(0) = (T(0)+1)/2 = 1 = fib(1) \\ S(1) = (T(1)+1)/2 = 1 = fib(2) \\ \end{cases} { S(0)=(T(0)+1)/2=1=fib(1)S(1)=(T(1)+1)/2=1=fib(2)

也就是说,S(n)=fib(n+1)

进而:
S(n)=fib(n+1)=(ϕn+1−ϕ^n+1)/5, ϕ=(1+5)/2, ϕ^=(1−5)/2T(n)=2∗S(n)−1=2∗fib(n+1)−1=O(ϕn+1)≈O(2n) \begin{aligned} & S(n)=fib(n+1)=(\phi^{n+1}-\hat{\phi}^{n+1})/\sqrt{5},\ \phi = (1+\sqrt{5})/2,\ \hat{\phi}=(1-\sqrt{5})/2 \\ & T(n) = 2*S(n)-1 = 2*fib(n+1)-1=O(\phi^{n+1})\approx O(2^n) \\ \end{aligned} S(n)=fib(n+1)=(ϕn+1ϕ^n+1)/5 , ϕ=(1+5 )/2, ϕ^=(15 )/2T(n)=2S(n)1=2fib(n+1)1=O(ϕn+1)O(2n)

也就是说,二分递归的算法时间复杂度达到了恐怖的指数量级,而这个结果是远远不能被接受的(关于 φ 值是如何计算得出的稍后详解)。

如果说指数级复杂度,是给这个算法做了定性分析,那么我们定量举个例子。

最普通的 PC 运算性能大致为 1GHz,意味着每秒可以做 10^9 次浮点预算,也就是十亿次。

当我们计算第 100 项斐波那契数时,大约需要 2^100 次运算,那么大概耗时为 2^100 /10^9 ,这是多少呢?

粗略估算,2^10 也就是 1024,约等于 10^3,也就是 1000

那么:

2100=(210)10≈(103)102100/109≈(103)10/109=1021 \begin{aligned} & 2^{100} = (2^{10})^{10} \approx (10^3)^{10} \\ & 2^{100}/10^9 \approx (10^3)^{10}/10^9 = 10^{21} \\ \end{aligned}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值