广告
返回顶部
首页 > 资讯 > 前端开发 > html >什么是递归算法
  • 826
分享到

什么是递归算法

2024-04-02 19:04:59 826人浏览 独家记忆
摘要

这篇文章主要介绍“什么是递归算法”,在日常操作中,相信很多人在什么是递归算法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”什么是递归算法”的疑惑有所帮助!接下来,请跟着小编一

这篇文章主要介绍“什么是递归算法”,在日常操作中,相信很多人在什么是递归算法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”什么是递归算法”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

递归求斐波那契数列的性能分析

先来看一下求斐波那契数的递归写法。

int fibonacci(int i) {        if(i <= 0) return 0;        if(i == 1) return 1;        return fibonacci(i-1) + fibonacci(i-2); }

对于递归算法来说,代码一般都比较简短,从算法逻辑上看,所用的存储空间也非常少,但运行时需要内存可不见得会少。

时间复杂度分析

来看看这个求斐波那契的递归算法的时间复杂度是多少呢?

在讲解递归时间复杂度的时候,我们提到了递归算法的时间复杂度本质上是要看: 递归的次数 * 每次递归的时间复杂度。

可以看出上面的代码每次递归都是O(1)的操作。再来看递归了多少次,这里将i为5作为输入的递归过程 抽象成一颗递归树,如图:

什么是递归算法

从图中,可以看出f(5)是由f(4)和f(3)相加而来,那么f(4)是由f(3)和f(2)相加而来 以此类推。

在这颗二叉树中每一个节点都是一次递归,那么这棵树有多少个节点呢?

我们之前也有说到,一棵深度(按根节点深度为1)为k的二叉树最多可以有 2^k - 1 个节点。

所以该递归算法的时间复杂度为 O(2^n) ,这个复杂度是非常大的,随着n的增大,耗时是指数上升的。

来做一个实验,大家可以有一个直观的感受。

以下为c++代码,来测一下,让我们输入n的时候,这段递归求斐波那契代码的耗时。

#include <iOStream> #include <chrono> #include <thread> using namespace std; using namespace chrono; int fibonacci(int i) {        if(i <= 0) return 0;        if(i == 1) return 1;        return fibonacci(i - 1) + fibonacci(i - 2); } void time_consumption() {     int n;     while (cin >> n) {         milliseconds start_time = duration_cast<milliseconds >(             system_clock::now().time_since_epoch()         );          fibonacci(n);          milliseconds end_time = duration_cast<milliseconds >(             system_clock::now().time_since_epoch()         );         cout << milliseconds(end_time).count() - milliseconds(start_time).count()             <<" ms"<< endl;     } } int main() {     time_consumption();     return 0; }

根据以上代码,给出几组实验数据:

测试电脑以2015版MacPro为例,CPU配置:2.7 GHz Dual-Core Intel Core i5

测试数据如下:

  • n = 40,耗时:837 ms

  • n = 50,耗时:110306 ms

可以看出,O(2^n)这种指数级别的复杂度是非常大的。

所以这种求斐波那契数的算法看似简洁,其实时间复杂度非常高,一般不推荐这样来实现斐波那契。

其实罪魁祸首就是这里的两次递归,导致了时间复杂度以指数上升。

return fibonacci(i-1) + fibonacci(i-2);

可不可以优化一下这个递归算法呢。主要是减少递归的调用次数。

来看一下如下代码:

// 版本二 int fibonacci(int first, int second, int n) {     if (n <= 0) {         return 0;     }     if (n < 3) {         return 1;     }     else if (n == 3) {         return first + second;     }     else {         return fibonacci(second, first + second, n - 1);     } }

这里相当于用first和second来记录当前相加的两个数值,此时就不用两次递归了。

因为每次递归的时候n减1,即只是递归了n次,所以时间复杂度是 O(n)。

同理递归的深度依然是n,每次递归所需的空间也是常数,所以空间复杂度依然是O(n)。

代码(版本二)的复杂度如下:

  • 时间复杂度:O(n)

  • 空间复杂度:O(n)

此时再来测一下耗时情况验证一下:

#include <iostream> #include <chrono> #include <thread> using namespace std; using namespace chrono; int fibonacci_3(int first, int second, int n) {     if (n <= 0) {         return 0;     }     if (n < 3) {         return 1;     }     else if (n == 3) {         return first + second;     }     else {         return fibonacci_3(second, first + second, n - 1);     } }  void time_consumption() {     int n;     while (cin >> n) {         milliseconds start_time = duration_cast<milliseconds >(             system_clock::now().time_since_epoch()         );          fibonacci_3(0, 1, n);          milliseconds end_time = duration_cast<milliseconds >(             system_clock::now().time_since_epoch()         );         cout << milliseconds(end_time).count() - milliseconds(start_time).count()             <<" ms"<< endl;     } } int main() {     time_consumption();     return 0; }

测试数据如下:

  • n = 40,耗时:0 ms

  • n = 50,耗时:0 ms

大家此时应该可以看出差距了!!

空间复杂度分析

说完了这段递归代码的时间复杂度,再看看如何求其空间复杂度呢,这里给大家提供一个公式:递归算法的空间复杂度 = 每次递归的空间复杂度 *  递归深度

为什么要求递归的深度呢?

因为每次递归所需的空间都被压到调用栈里(这是内存管理里面的数据结构,和算法里的栈原理是一样的),一次递归结束,这个栈就是就是把本次递归的数据弹出去。所以这个栈最大的长度就是递归的深度。

此时可以分析这段递归的空间复杂度,从代码中可以看出每次递归所需要的空间大小都是一样的,所以每次递归中需要的空间是一个常量,并不会随着n的变化而变化,每次递归的空间复杂度就是O(1)。

在看递归的深度是多少呢?如图所示:

什么是递归算法

递归第n个斐波那契数的话,递归调用栈的深度就是n。

那么每次递归的空间复杂度是O(1), 调用栈深度为n,所以这段递归代码的空间复杂度就是O(n)。

int fibonacci(int i) {        if(i <= 0) return 0;        if(i == 1) return 1;        return fibonacci(i-1) + fibonacci(i-2); }

最后对各种求斐波那契数列方法的性能做一下分析,如题:

什么是递归算法

可以看出,求斐波那契数的时候,使用递归算法并不一定是在性能上是最优的,但递归确实简化的代码层面的复杂度。

二分法(递归实现)的性能分析

带大家再分析一段二分查找的递归实现。

int binary_search( int arr[], int l, int r, int x) {     if (r >= l) {         int mid = l + (r - l) / 2;         if (arr[mid] == x)             return mid;         if (arr[mid] > x)             return binary_search(arr, l, mid - 1, x);         return binary_search(arr, mid + 1, r, x);     }     return -1; }

都知道二分查找的时间复杂度是O(logn),那么递归二分查找的空间复杂度是多少呢?

我们依然看 每次递归的空间复杂度和递归的深度

首先我们先明确这里的空间复杂度里面的n是什么?二分查找的时候n就是指查找数组的长度,也就是代码中的arr数组。

每次递归的空间复杂度可以看出主要就是参数里传入的这个arr数组,即:O(n)。

再来看递归的深度,二分查找的递归深度是logn ,递归深度就是调用栈的长度,那么这段代码的空间复杂度为 n * logn = O(nlogn)。

有同学问了:为什么网上很多人说递归二分查找的空间复杂度是O(logn),而不是O(nlogn)呢?

其实还是因为这个数组,我们可以把这个数组放到外面而不是放在递归函数参数里里,代码如下:

int arr[] = {2, 3, 4, 5, 8, 10, 15, 17, 20}; int binary_search(int l, int r, int n) {     if (r >= l) {         int mid = l + (r - l) / 2;         if (arr[mid] == n)             return mid;         if (arr[mid] > n)             return binary_search(l, mid - 1, n);         return binary_search(mid + 1, r, n);     }     return -1; }

看这份代码将arr数组定义为全局变量,而不放在递归循环里,那么每层递归的空间复杂度是O(1),递归深度为O(logn),整体空间复杂度为 1 * logn  = O(logn)。

到此,关于“什么是递归算法”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: 什么是递归算法

本文链接: https://www.lsjlt.com/news/83364.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 什么是递归算法
    这篇文章主要介绍“什么是递归算法”,在日常操作中,相信很多人在什么是递归算法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”什么是递归算法”的疑惑有所帮助!接下来,请跟着小编一...
    99+
    2022-10-19
  • python中什么是递归算法
    本篇文章为大家展示了python中什么是递归算法,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。python主要应用领域有哪些1、云计算,典型应用OpenStack。2、WEB前端开发,众多大型网站均...
    99+
    2023-06-14
  • 递归算法的时间复杂度是什么
    递归算法的时间复杂度取决于递归的深度以及每次递归的时间复杂度。如果递归的深度为n,每次递归的时间复杂度为T,那么递归算法的时间复杂度...
    99+
    2023-08-28
    递归算法
  • java递归算法怎么用
    这篇文章给大家分享的是有关java递归算法怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。递归算法设计的基本思想是:对于一个复杂的问题,把原问题分解为若干个相对简单类同的子问题,继续下去直到子问题简单到能够直...
    99+
    2023-05-30
    java
  • Java递归算法详解
    递归算法是一种通过调用自身来解决问题的方法。在Java中,递归算法通常有以下几个要素:1. 基本情况:递归方法必须有一个基本情况,即...
    99+
    2023-09-14
    Java
  • java递归算法实例
    递归三要素:明确递归终止条件;给出递归终止时的处理办法;提取重复的逻辑,缩小问题规模。1、1+2+3+…+nimport java.util.Scanner; public class Recursion { public sta...
    99+
    2018-06-15
    java入门 java 递归算法
  • C# 递归算法详解
    目录1)1、1、2、3、5、8.......用递归算法求第30位数的值?2)编写计算斐波那契(Fibonacci)数列的第n项函数fib(n)斐波那契数列为:0、1、1、2、3、……...
    99+
    2022-11-12
  • C#递归算法和排列算法
    一、递归算法 递归:你打开面前这扇门,看到屋里面还有一扇门。你走过去,发现手中的钥匙还可以打开它,你推开门,发现里面还有一扇门,你继续打开它。若干次之后,你打开面前的门后,发现只有一...
    99+
    2022-11-13
  • vb递归算法怎么使用
    VB递归算法使用步骤如下:1. 定义一个递归函数,函数中包含递归调用。2. 判断递归终止条件,即递归函数不再调用自身的条件。3. 在...
    99+
    2023-06-10
    vb递归算法
  • Python中递归算法怎么用
    小编给大家分享一下Python中递归算法怎么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!递归是一种较为抽象的数学逻辑,可以简单的理解为「程序调用自身的算法」。...
    99+
    2023-06-29
  • java递归算法怎么应用
    Java递归算法可以应用于以下场景:1. 阶乘计算:递归可以用来计算一个数的阶乘。例如,计算n的阶乘可以定义为f(n) = n * ...
    99+
    2023-08-09
    java
  • 这么看待PHP递归算法
    这篇文章将为大家详细讲解有关这么看待PHP递归算法,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。PHP还是比较常用的,于是我研究了一下PHP递归算法,在这里拿出来和大家分享一下,希望对大家有...
    99+
    2023-06-17
  • Python递归算法怎么应用
    递归算法是一种通过调用函数本身来解决问题的方法。在Python中,递归算法可以应用于各种问题,例如计算阶乘、斐波那契数列等。下面是一...
    99+
    2023-08-15
    Python
  • 基于Java递归算法的封装解决方法是什么
    本篇内容介绍了“基于Java递归算法的封装解决方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、递归算法1、概念简介递归算法的核心...
    99+
    2023-06-02
  • Java二叉树的递归和非递归遍历方法是什么
    本篇内容主要讲解“Java二叉树的递归和非递归遍历方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java二叉树的递归和非递归遍历方法是什么”吧!前言二叉树的遍历方法分为前序遍历,中序遍...
    99+
    2023-06-30
  • Java递归算法与优化后的算法有什么区别
    本篇内容介绍了“Java递归算法与优化后的算法有什么区别”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、...
    99+
    2022-10-19
  • Java的递归算法详解
    目录一、介绍1、介绍2、案例二、迷宫问题三、八皇后问题四、汉诺塔问题1、问题2、思想3、代码总结一、介绍 1、介绍 递归:递归就是方法自己调用自己,每次调用时传入不同的变量。递归有助...
    99+
    2022-11-12
  • 递归算法时间复杂度怎么算
    递归算法的时间复杂度可以通过递归树来计算。递归树是一个树形结构,表示递归算法的执行过程。树的根节点表示原始问题,每个节点表示递归调用...
    99+
    2023-05-30
    递归算法时间复杂度 递归算法
  • Java的递归算法怎么优化
    优化递归算法可以通过以下方法来实现:1. 尾递归优化:尾递归是指递归函数在调用自身之后没有其他的操作,直接返回递归函数的结果。尾递归...
    99+
    2023-08-15
    Java
  • c#递归算法代码怎么写
    在C#中,可以使用递归算法来解决一些问题。递归算法是一种自我调用的算法,它将问题分解为更小的子问题,并通过递归调用解决这些子问题,最...
    99+
    2023-08-09
    c#
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作