C++语言基础--递归函数

2023-11-04

对于很多编程初学者来说,递归算法是学习语言的最大障碍之一。可能也有一大部分人知道递归,也能看的懂递归,但在实际做题过程中,却不知道怎么使用

递归的定义

1、很官方的说法
递归,在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。
也就是说,递归算法是一种直接或者间接调用自身函数或者方法的算法。
2、递归的核心思想
通俗来说,递归算法的实质是把问题分解成规模缩小的同类问题的子问题,然后递归调用方法来表示问题的解。
这就是分治的思想
3、递归的自我感觉

以下纯是个人感受,递归可以视为循环的扩展,我们利用计算机的高速运算能力可以使用循环,让计算机重复做某些事情,当这些事情可以封装成函数,且模式一样,就可以使用递归进行解决了。

递归是程序运行时的一种现象,也是解决某些特定问题时较迭代算法来说更自然更优雅的代码组织方式。
在这里插入图片描述
4、递归的时间复杂度

递归可以使用递归树或者主定理去求解,需要多做题去掌握。

递归的三大要素

第一要素:明确你这个函数想要干什么。先不管函数里面的代码什么,而是要先明白,你这个函数的功能是什么,要完成什么样的一件事。

第二要素:寻找递归结束条件。我们需要找出当参数为啥时,递归结束,之后直接把结果返回,请注意,这个时候我们必须能根据这个参数的值,能够直接知道函数的结果是什么。

第三要素:找出函数的等价关系式。我们要不断缩小参数的范围,缩小之后,我们可以通过一些辅助的变量或者操作,使原函数的结果不变。(分治的思想,大规模问题化解成小规模问题,直到化成单一问题进行解决

递归的过程

在这里插入图片描述

void foo()
{
    // 自己调用自己就是递归
    foo();
}

我们知道这个函数要是运行起来,除了让你的程序报出一个「堆栈溢出」的错误外,其他什么作用也没有。在某种程度上说,我们的大脑就是一个计算机。
当我们尝试去理解「自己调用自己」这句话时,大脑也会陷入一个无限的递归过程里,然后「轰」的一声「堆栈溢出」了,所以也就无法去理解了。当然老师还会告诉你递归除了「自己调用自己」外,还有很重要的一部分就是在满足条件的时候函数会返回,这样就避免出现无限递归的过程了。所以一个完整的递归函数组成如下:

void foo()
{
    // 返回部分
    if (condition)
    {
        return;
    }
    
    // 递归部分
    foo();
}

例如:递归求斐波那契数列
在这里插入图片描述

从上面的步骤我们可以清晰的看到递归算法的第一步是分治,把复杂的大的问题,给拆分成一个一个小问题,直到不能再拆解,通过退出条件retrun,然后再从最小的问题开始解决,只到所有的子问题解决完毕,那么最终的大问题就迎刃而解。

1、把问题分解成更容易解决的子问题集合,比如可以把计算斐波那契数列的第n项问题分解转换成计算第n-1项加上第n-2项这两个子问题
2、 假设我们有一个函数可以应用在所有的子问题上,比如计算斐波那契数列的fib函数
3、基于步骤2的函数,实现如何把子问题的解拼成最终问题的解,这就是递归部分,在计算斐波那契数列的例子里就是fib(n-1) +fib(n-2)部分
4、递归部分确定了,然后再考虑子问题最终简化到到最底层时该返回什么值。
5、上面4步都做好了之后,剩下的就只是毫无条件的相信计算机了……

例二实现一个函数翻转给定的字符串。
假设我们要翻转的字符串是“abcdef”,那么翻转之后的结果应该是“fedcba”。
毫无疑问这个字符串我们是没办法一下子就翻转过来的,那么「分而治之」吧。
我们不能把多个字符一下子就完全翻转过来,但是假如字符串里的字符只有一个呢?
我们翻转起来最方便了,因为什么都不用做。好了,我们可以把”abcdef“分解成”a“和”bcdef“两个子字符串。”bcdef“比”abcdef“短一个字符,理论上也稍微容易点。假设我们有这样的函数能接受一个字符串,然后像变戏法一样就能返回一个翻转后的字符串,如下:

 string revertString(const string& str)
{
    // str = 'abcdef'
    // str[0] = 'a'
    // str.substr(1) = 'bcdef'
    return revertString(str.substr(1)) + str[0];
}

当然现在这个函数还不能直接交给计算机去执行,因为我们传给revertString的参数字符串在不断的缩短,当缩短到一个字符或者一个字符也没有时,我们就没办法再继续缩短了,我们要把这些情况也处理掉才行:

string revertString(const string& str)
{
    if (str.length() <= 1) {
        return str;
    }
    // str = 'abcdef'
    // str[0] = 'a'
    // str.substr(1) = 'bcdef'
    return revertString(str.substr(1)) + str[0];
}

好了,这样的一个函数就可以交给计算机去执行了,然后剩下的事情就是「见证奇迹」的时刻了。以上的思维过程可以应用于绝大多数递归算法上。

课后练习很重要哦

1、利用递归求N!(N的阶乘)
2、上台阶
3、最大公约数GCD

三道练习题目视频讲解地址
1、洛谷P1010-2的幂次方

2的幂次方P1010

2、洛谷P5461-赦免战俘

赦免战俘-洛谷P5461

3、洛谷T218202-农场周围的路

农场周围的路--洛谷T218202

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++语言基础--递归函数 的相关文章

  • 如果有一条告警流量你会怎么分析,请详细说明?

    先要判断攻击有没有成功 是攻击成功的告警 还是攻击不成功但是真实的攻击 看规则的告警的名称 分析攻击源IP和目的IP 如果攻击源IP是内网的话 则可能为有关键特征的业务系统 被判为恶意攻击 内网可能沦陷 已被入侵 可能是设备使用盗版软件或者

随机推荐

  • Yolov5的安装配置与使用

    文章目录 一 下载Yolov5 1 下载Yolov5源码 2 下载Yolov5预训练模型 二 安装Yolov5 三 测试Yolov5 1 Img图片测试 2 Video视频测试 3 摄像头测试 三 小结 四 参考链接 在下载配置Yolov5
  • Echarts 实现两个图表联动

    init obj pageSource var that this console log obj pageSource this chart this echarts init document getElementById this i
  • 使用C++ Eigen库求解线性方程组Ax=b

    Eigen http eigen tuxfamily org 是常用的 C 矩阵运算库 具有很高的运算效率 大部分 需要在 C 中使用矩阵运算的库 都会选用 Eigen 作为基本代数库 例如 Google Tensorflow Google
  • 批量读取csv文件指定列

    目录 一 算法原理 二 代码实现 三 注意事项 一 算法原理 在读取csv文件进行点云处理的时候 常常需要跳过表头 并且进行批量读取 本代码 将每行数据记录为一个数组 并将多个csv文件合并记录 在使用中 需要自己修改想要提取的列数以及定义
  • FM33LG0XX-16位基本定时器

    FM33LG0包含1个16位基本定时器 基本定时器包含一个16bit自动重载计数器及一个可编程预分频器 基本定时器主要用来产生系统时基 也可以产生触发事件来驱动ADC采样 测试代码如下 void BSTIM Init uint16 t pr
  • 【转载收藏】Unity预计算实时GI

    初步介绍 新年假期结束了 想不想掌握一个新技能迎接全新的一年呢 不妨来阅读一下Unity预计算实时GI系列文章 本文是该系列的第一篇 在Unity中有两种区别很大的技术被用于计算全局光照GI或光源反射 它们就是烘焙全局光照 Baked GI
  • 【一文搞懂】FD_SET的使用

    阅读大概需要十分钟 绝对干货 看完还没搞懂你找我 随便查一下 可以看到对FD SET的说明如下 一个long类型的数组 提供给select 机制使用的一种数据结构 主要功能是建立联系 其中每一个数组元素都能与任意一个打开的句柄 socket
  • 回溯法(基础版)

    能进则进 不能进则换 不能换则退 退一步海阔天空 文章目录 算法适用问题 算法思想步骤 基础题目 A 装载问题 B 0 1背包问题 C N皇后问题 D 涂色问题 算法适用问题 搜索问题 求解的个数 最优解问题 算法思想步骤 深度优先搜索 定
  • js实现圆型的进度条

    一次项目需求中需要实现一个圆形的进度条 就参考了网上的一些资料做了一个demo 具体代码如下
  • Java线程池七大参数详解和配置

    目录 一 corePoolSize核心线程数 二 maximunPoolSize最大线程数 三 keepAliveTime空闲线程存活时间 四 unit空闲线程存活时间的单位 五 workQueue线程工作队列 1 ArrayBlockin
  • Mac如何读写NTFS硬盘,NTFSTool让Mac也可以轻松读写NTFS硬盘

    在了解Mac如何读写NTFS格式硬盘前 我们应该先了解什么是NTFS硬盘 以及Mac为什么不能对NTFS硬盘进行读写 一 什么是NTFS硬盘 NTFS格式硬盘最早出现于1993年的win NT操作系统中 作为一款日志文件系统 除了可以对硬盘
  • Java中 判断集合中的元素相等的依据 详细解析

    我们经常使用的集合如ArrayList LinkedList Vector 你在调用contains 方法的时候 或者是你在根据对象移除元素 remove Object o 你知道他们是如何判断集合中的元素是否 是相等的吗 接下来我们跟着源
  • 解决Linux MySQL报错ERROR 2002

    在Linux安装MySQL有时候会出现 mysql ERROR 2002 HY000 Can t connect to local MySQL server through socket var lib mysql mysql sock 2
  • Fority代码审计工具介绍

    Fortify SCA简介 Fortify SCA 是一个静态的 白盒的软件源代码安全测试工具 它通过内置的五大主要分析引擎 数据流 语义 结构 控制流 配置流等对应用软件的源代码进行静态的分析 分析的过程中与它特有的软件安全漏洞规则集进行
  • 速度教你创建网页文件,实现HTML入门

    今天 为大家准备了关于创建网页文件的学习内容 具体包括网页文件创建 HTML标签语法规范 HTML标签的关系以及HTML整体结构 完成以上内容的学习 零基础学习者基本上就能学会如何创建一个有简单内容的网页文件 快一起来看吧 1 网页文件的扩
  • Java常用包

    Java采用包结构来组织和管理类和接口文件 一 java lang包 该包提供了Java语言进行程序设计的基础类 它是默认导入的包 该包里面的Runnable接口和Object Math String StringBuffer System
  • Python中使用zlib库实现字符串的压缩和解压缩是一种常见的操作

    Python中使用zlib库实现字符串的压缩和解压缩是一种常见的操作 zlib库提供了一组函数 可以方便地对字符串进行压缩和解压缩操作 下面是一个详细的示例 展示了如何使用zlib库进行字符串的压缩和解压缩 首先 我们需要导入zlib库 i
  • C++模板的使用

    在平时的工作和学习过程中 经常会用到泛型 这里对泛型和模板进行一下梳理 以便理解和使用 模板关键字 template 为什么要使用模板 假如设计一个两个参数的函数 用来求两个对象的乘积 在实践中我们可能需要定义n多个函数 int multi
  • ETCD v3 restful api 使用详解

    ETCD v3 restful api 使用详解 网上已经有很多关于v2接口的使用了 类型下面的请求方式 本文就主要讲解v3版本的restful api的使用方式 V2版本 curl http 127 0 0 1 2379 v2 keys
  • C++语言基础--递归函数

    对于很多编程初学者来说 递归算法是学习语言的最大障碍之一 可能也有一大部分人知道递归 也能看的懂递归 但在实际做题过程中 却不知道怎么使用 递归的定义 1 很官方的说法 递归 在数学与计算机科学中 是指在函数的定义中使用函数自身的方法 也就