| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> 深入理解递归函数 -> 正文阅读 |
|
[数据结构与算法]深入理解递归函数 |
1.递归函数概念介绍以及个人对递归的理解先给出一个概念: 递归函数:我们把一个直接调用自己或通过一系列的调用语句间接地调用自己的函数,称做递归函数。 一直都对递归有种敬畏之情,因为之前在一家公司里是不让写递归的,我记得当时的理由是递归代码比较晦涩,所以自己也就一直没有对递归深入的了解,但是随着时间的推移,我感觉有的时候,用递归写的代码是优雅的,递归应该算作是一种算法,或者编程技巧。当然递归也有自己的缺点,它会有函数间的不断调用,函数调用栈是比较消耗时间和内存的,同时如果递归结束条件写的不对,也会造成内存被爆,程序崩溃的可能,但是凡事都是相对的,你要想用递归的优雅,简洁的代码结构,也就必然要承担她的缺点,凡事都是两面的。但是至于说递归晦涩难懂,现在看来这个感觉说法是站不住脚的,如果,你真正理解递归的过程,我感觉应该会让你恍然大悟,有一种妙哉妙哉的感觉,因为递归能使程序的结构更加的清晰,更简洁,更容易让人理解,从而减少读代码的时间。 所谓递归,就是递 和 归,递就是前行的阶段,归就是退回的阶段。那么问题来了,前行的时候做了什么,什么时候回来,退回的时候又做了什么?那我们带着问题继续阅读吧! 2.递归与栈的关系简单的说,在递归的前行阶段,对于每一层递归,函数的局部变量,参数值,以及返回地址都被压入栈中,在退回阶段,对于栈顶顶局部变量,参数值,和返回地址被弹出,用于返回调用层次中执行代码的其余部分,也就是恢复了调用的状态。 3.通过一个例子观察递归,通过阶乘观察递归过程这个例子主要参考了我在文章末尾附的链接。 每个递归函数都有终止条件和递归条件两个部分:终止条件,表示停止调用自己,避免无限循环;递归条件是指继续调自己。 接下来结合调用栈来理解,先看下面一段代码,表示计算阶乘的递归函数:
理解了代码之后,我们假如求 fact (3),看看计算机到底是怎么执行上面一段函数的。 ?当程序不满足 if 条件是,进入else,开始递归,第二次调用fact,传入 x = 2 : ?第二次调用结束之后,开始第三次调用,传入 x = 1,满足 if x == 1 的条件,继续执行 return 1,这时我们可以知道 fact(1)这个函数的返回值是 1 ,即fact(1)= 1。 以上的x == 1就是递归的结束条件,else 之后就是递归条件。当满足基准条件之后,笑脸之后表示开始所谓的“归”的过程。 好了,到此位置,我们的第一个简单的递归例子就详细描述完了,这个例子是比较容易接受的例子,后面我会详细的讲述,什么情况下使用递归,以及再来几个,斐波那些数列,以及二叉树的例子来理解递归这个问题。 4.什么情况下使用递归?递归需要满足的三个条件: a.一个规模大问题的解可以分解成几个规模较小问题的解 b.规模大问题和规模小问题的求解思路完全一样 c.存在递归终止条件 以上三个条件既涉及到分而治之的思想,又涉及到递归。我们再通过几个例子来加深对三个条件的理解。 4.1 斐波那契数列 说如果兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来,假设所有兔都不死,那么一年以后可以繁殖多少对兔子呢? 4.2 判断一个二叉树是否是对称 题干如下: 请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。 例如,二叉树?[1,2,2,3,4,4,3] 是对称的。 ? ? 1 ????1 现在我们来通过我们之前得到的结论来分析这个问题是否可以使用递归: a.一个规模大问题的解可以分解成几个规模较小问题的解 b.规模大问题和规模小问题的求解思路完全一样 c.存在递归终止条件 首先,这个符合条件a,也就是,这个规模比较大的问题,可以差分成下面规模小的问题。 然后我们再看条件b 规模大的问题和规模小的问题求解思路完全相同,但是有一个特例,就是对于根结点的处理,因为根只有一个值,不能有两个参数,所以这个要特殊处理下。 这个也是很关键的一步,在对于这个递归问题的时候,很多时候,一些特例要提取出来,不能放在递归中。 c.存在递归结束条件 当 L 和 R 同时越过叶节点: 此树从顶至底的节点都对称,因此返回 true ; 算法流程: 1.特例处理: 若根节点 root 为空,则直接返回 true?。 2.终止条件: 具体实现代码如下:
4.3? 求二叉树的路径和 给你二叉树的根节点?root 和一个表示目标和的整数?targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和?targetSum 。如果存在,返回 true ;否则,返回 false 。 叶子节点 是指没有子节点的节点。 对于这个问题,我感觉难点是怎么把大问题分解成小的问题。 思路及算法 观察要求我们完成的函数,我们可以归纳出它的功能:询问是否存在从当前节点 root 到叶子节点的路径,满足其路径和为 sum。 假定从根节点到当前节点的值之和为 val,我们可以将这个大问题转化为一个小问题:是否存在从当前节点的子节点到叶子的路径,满足其路径和为 sum - val。 不难发现这满足递归的性质,若当前节点就是叶子节点,那么我们直接判断 sum 是否等于 val 即可(因为路径和已经确定,就是当前节点的值,我们只需要判断该路径和是否满足条件)。若当前节点不是叶子节点,我们只需要递归地询问它的子节点是否能满足条件即可。 代码如下:
参考链接: |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 5:58:50- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |