← PHP中回文数的判定:数字反转与比较 PHP中数字反转的两种方法:数学算法与字符串函数 →

PHP中斐波那契数列的两种实现:迭代与递归

原创 2026-05-21 PHP 已有人查阅

什么是斐波那契数列

斐波那契数列(Fibonacci sequence)是一组数字序列,其中每个数字是它前面两个数字之和。这个数列的起始两个数字通常定义为0和1。

数列展示:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89……

计算过程

  • 第1项:0(起始值)

  • 第2项:1(起始值)

  • 第3项:0 + 1 = 1

  • 第4项:1 + 1 = 2

  • 第5项:1 + 2 = 3

  • 第6项:2 + 3 = 5

  • 以此类推

在数学上,斐波那契数列常被用来演示递归思想。不过在编程中,迭代方式往往更实用。这一点后面会详细说明。

核心实现逻辑

斐波那契数列的生成需要三个关键变量:

  • $n1:前一个数(初始为0)

  • $n2:当前数(初始为1)

  • $n3:下一个数($n1 + $n2

每次迭代中,将$n1$n2向前推进:

  1. 计算$n3 = $n1 + $n2

  2. 输出$n3

  3. $n2赋值给$n1

  4. $n3赋值给$n2

  5. 重复以上步骤

示例一:使用while循环输出前12个斐波那契数

代码号学习编程的初学者通常先从循环版本开始理解。

<?php  
$count = 0;      // 已输出的数字个数(不包括前两个)
$first = 0;  
$second = 1;  

echo "<h3>斐波那契数列前12个数:</h3>";  
echo $first . " " . $second . " ";  

while ($count < 10) {       // 已经输了2个,还需要再输出10个,总共12个
    $next = $second + $first;  
    echo $next . " ";  
    $first = $second;  
    $second = $next;  
    $count = $count + 1;  
}  
?>

输出0 1 1 2 3 5 8 13 21 34 55 89

为什么循环条件是$count < 10而不是12:因为前两个数字01已经在循环之前输出了,剩下的10个数字需要在循环中生成。这个细节容易搞错,很多人会写成$count < 12导致输出了14个数字。

示例二:使用for循环的简洁写法

for循环在处理已知次数的迭代时更加紧凑。

<?php
$first = 0;
$second = 1;
$terms = 12;   // 要输出的项数

echo "斐波那契数列前{$terms}个数:";
echo $first . " " . $second . " ";

for ($i = 3; $i <= $terms; $i++) {   // 从第3项开始计算
    $next = $first + $second;
    echo $next . " ";
    $first = $second;
    $second = $next;
}
?>

个人经验:用for循环时,我习惯让循环变量从3开始,这样与项数的对应关系更清晰:i=3时生成第3项,i=4时生成第4项……读代码的人一眼就能看出逻辑,不需要额外注释。

示例三:使用递归方法实现斐波那契数列

递归(Recursion)指的是一个函数在其定义内部调用自身。斐波那契数列的数学定义本身就是递归形式:F(n) = F(n-1) + F(n-2)

<?php  
/* 递归函数:返回第n个斐波那契数 */  
function fibonacci($n) {  
    if ($n == 0) {  
        return 0;  
    } elseif ($n == 1) {  
        return 1;  
    } else {  
        return fibonacci($n - 1) + fibonacci($n - 2);  
    }   
}  

$num = 12;  
echo "<h3>使用递归方法输出前12个斐波那契数:</h3>";  

for ($i = 0; $i < $num; $i++) {  
    echo fibonacci($i) . " ";  
}  
?>

输出0 1 1 2 3 5 8 13 21 34 55 89

本节课程知识要点

知识点 说明
迭代与递归 两种实现思路,迭代效率更高,递归更符合数学定义
状态更新顺序 必须先更新$first再更新$second,顺序反了会导致计算错误
递归基线条件 $n == 0 和 $n == 1 是终止条件,防止无限递归
时间复杂度 递归版本O(2ⁿ)效率极低,迭代版本O(n)

迭代与递归的选择建议

递归版本的严重问题

递归方法虽然代码看起来简洁,但存在一个实际的问题——重复计算。以计算fibonacci(5)为例:

fibonacci(5) = fibonacci(4) + fibonacci(3)
fibonacci(4) = fibonacci(3) + fibonacci(2)
fibonacci(3) = fibonacci(2) + fibonacci(1)
……

fibonacci(3)被计算了2次,fibonacci(2)被计算了3次。当n变大时,重复计算的次数呈指数级增长。计算fibonacci(40)时,函数调用次数可达3亿次以上,页面响应会变得非常缓慢。

我的个人建议

在PHP中生成斐波那契数列,优先使用迭代(循环)方式。递归方法虽然适合展示算法思想,但在项目中基本不会用它来做数值计算。除非配合记忆化(Memoization)技术——把计算过的结果缓存起来避免重复计算,但这已经超出了基础范围。

什么时候用递归更合适:处理树形结构(比如遍历文件夹目录、解析嵌套评论)、分治算法等场景,递归的代码表达力更强。但就斐波那契数列而言,迭代方式是更实在的选择。

常见问题与排查

问题1:输出结果只有0和1,没有后续数字

  • 原因:循环中更新$first$second的顺序写反了

  • 正确顺序:先更新$first为新值,再更新$second

问题2:递归版本运行时间过长甚至超时

  • 原因:没有使用缓存优化,重复计算量巨大

  • 解决:改用迭代版本,或使用数组缓存中间结果

问题3:数值超出整数范围

  • 说明:斐波那契数列增长速度很快,第93项就会超过64位整数上限

  • 解决:大数场景下使用BCMath扩展的任意精度函数

扩展:使用数组缓存优化递归

如果一定要用递归又想避免重复计算,可以借助数组做记忆化:

$cache = [];
function fibonacciMemo($n, &$cache) {
    if ($n <= 1) return $n;
    if (!isset($cache[$n])) {
        $cache[$n] = fibonacciMemo($n-1, $cache) + fibonacciMemo($n-2, $cache);
    }
    return $cache[$n];
}

这种方式把计算过的值存起来,避免重复递归,效率能提升很多。

个人经验分享

当年第一次接触递归时觉得这个写法很简洁,有种数学上的美感。但在一个实际项目中用递归计算斐波那契数列到第50项,页面直接超时。那次之后我对递归在数值计算中的应用变得更加谨慎。

后来了一个原则:如果一个问题能用循环清晰解决,就先考虑循环。递归的价值更多体现在处理“未知深度”的结构上,而不是纯粹的数学序列。这个经验分享给正在学习的各位,希望能帮你少走一些弯路。

← PHP中回文数的判定:数字反转与比较 PHP中数字反转的两种方法:数学算法与字符串函数 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号