我有两段代码来计算给定指数的斐波纳契数列.一个使用递归,另一个使用array.它运行这两个函数,并 echo 计算每个函数所需的时间:

<?php
//Calculate the index recursively
function fibonacciRecursiveAtIndex($num){
$num = 0 and $num = 1
    if($num == 0){
        return 0;
    } else if ($num == 1){
        return 1;
    } else {
        return fibonacciRecursiveAtIndex($num-1) + fibonacciRecursiveAtIndex($num-2);
    }
}

//Calculate non-recursively
function fibonacciAtIndex($num){
    $fibonacciArray = [0, 1];

    for($i = 2; $i < $num + 1; $i++){
        array_push($fibonacciArray, $fibonacciArray[$i - 1] + $fibonacciArray[$i - 2]);
    }
    
    return $fibonacciArray[$num];
}

//Recursion becomes noticeably slower for an index value above 15
$indexToCalculate = 40;

//Plug index into the fibonacciRecursiveAtIndex() function and output calculation time. 
$timeStart = microtime(true);
$valueAtIndex = fibonacciRecursiveAtIndex($indexToCalculate);
$timeEnd = microtime(true);
echo "Recursive(" . $indexToCalculate . ") = " . $valueAtIndex . " -- calculated in " . round(($timeEnd - $timeStart),7) . " s";

echo "<br><br>";

//Plug index into the fibonacciAtIndex() function and output calculation time. 
//The calculated time is several orders of magnitudes faster for large indices (index > 15).
$timeStart = microtime(true);
$valueAtIndex = fibonacciAtIndex($indexToCalculate);
$timeEnd = microtime(true);

echo "Fibonacci(" . $indexToCalculate . ") = " . $valueAtIndex . " -- calculated in " . round(($timeEnd - $timeStart),7) . " s";

运行此命令以计算索引为40的fibonaci序列需要大约4秒的递归时间,但数组方法计算索引为40的时间与计算索引为4的时间大致相同(即,在微秒量级上).

这种行为背后的原则是什么?它在这里是如何应用的?

推荐答案

因为您的递归方法的时间复杂度是O(2^n),而数组方法的时间复杂度是O(n),其中n是NO.斐波纳契序列中的元素.

递归一遍又一遍地计算相同的子问题.例如,

 fibo(5) = fibo(4) + fibo(3)
 fibo(4) = fibo(3) + fibo(2)
 fibo(3) = fibo(2) + fibo(1)

正如您在上面看到的,fibo(3)被多次计算,fibo(2)也是如此.如果你追查fibo的大数,你会注意到同一个子问题的许多计算一遍又一遍,使得时间复杂性更高,而且是指数级的.

因此,您的递归方法比循环方法需要更多的时间.

在数组方法中,任何子问题都不会计算一次以上,因为结果在之后被缓存,这使得它比递归问题更有效.

但是,您可以通过记忆(缓存)子问题的结果来提高递归函数的效率.这样,它将具有与数组方法相同的时间复杂性,但可能仍然有点慢(毫秒差异可以忽略不计),因为需要维护递归调用堆栈.

Php相关问答推荐

ngnix php8.0-fPM主要脚本未知

此行动未经授权.升级Laravel时

Symfony Monolog:使用多个格式化程序

如何隐藏x轴图表上的值

在ShipStation for WooCommerce中使用自定义订单项目元数据

将变体设置字段添加到WooCommerce中的特定变量产品

从WooCommerce订单状态更改更新用户自定义元数据

WordPress插件和JSON不是有效的响应错误

如果为布尔值,则 for each 循环重新启动

如何使用MS Graph PHP SDK V2下载文件

使用与OpenSSL命令行兼容的AES-256-CTR为大型文件创建php代码OpenSSL加密

如何使用barryvdh/laravel-Snappy在两个打印页面上将表格分成两部分?

除WooCommerce中的特定国家/地区外,有条件地要求填写邮政编码 checkout 字段

从 XAMPP 运行 shell 脚本时,意外标记(附近出现语法错误

PHP Symfony 在测试.env文件中将接口自动装配作为构造函数参数,但使用接口的特定类

WooCommerce checkout 流程中基于所选选项添加自定义费用

为什么在解压缩具有混合字符串和 int 键的关联数组时出现错误消息无法使用位置参数...?

PDO 和 SQL 查询结果中日期格式不同的原因可能是什么?

为什么 AJAX 请求没有通过 is_ajax_request() codeigniter 的条件?

Laravel Websockets 错误:(WebSocket 在建立连接之前关闭)