| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> 暴力递归的理解 -> 正文阅读 |
|
[数据结构与算法]暴力递归的理解 |
? @[TOC](文章目录) 前言递归是程序中很接近于数学语言的一种写法,使用递归编程在阅读代码易于理解,但是往往会带来效率低下的问题,效率问题暂且按下不表,本章主要讲讲对于递归的理解 提示:以下是本篇文章正文内容,下面案例可供参考 一、递归是什么?百度解释:程序调用自身的编程技巧称为递归( recursion)。在百度还有更细致的解释,我在这里就不多加赘述,我在这里谈谈自己的理解:可以理解在整个问题中有重叠的子问题,什么叫重叠子问题呢?即一个问题是不独立的,一个子问题在下一个阶段决策中可能会不停的用到。我在上面提到递归很接近数学语言,我就用数学公式公式举例:比如常用到的函数? f(n)=? f(n-1)+x; 那么f(n-1)就是f(n)的一个重叠子问题,它们有着相同的逻辑,只是参数由n变为n-1。 二、使用步骤三要素那么如何写一个递归的问题呢?经过无数前辈的不断总结,得到如下的三个要素: 第一要素:明确这个函数要干什么 第二要素:寻找递归结束条件 第三要素:找出函数的等价关系式 其实你可以简单理解记忆为哲学三问:我是谁(明确这个函数要干什么),我从哪里来(寻找递归结束条件),我要到哪里去(找出函数的等价关系式),在下面的解释过程中,我们以举例子的形式来描述这三个过程,一般会以比较简单的斐波那契数列来举例,但是我认为这个过于简单就像一个数学公式一样,你太轻易的理解公式,反而很难去真的理解递归的过程,所有我们以一个反转链表来举例,第一 它的递归条件不是一个简单的数字变换,需要一定的理解 第二 我个人对于递归有个入门的理解,就来源于这个程序的编写。 2.1?明确这个函数要干什么第一要素:明确这个函数要干什么 千万不要小看这一过程,就像你要做一件事情,你都没有准确的弄清楚你到底要干什么,那么你的结果很大概率上会失败,没有这个过程,你下面的程序将很难继续下去,同样在使用递归的过程中,你也要准确的定义这个函数到底要干什么,记住是准确定义,举个例子,数学中常用的 f(x),但是但是在不同的场合它所表达的意义也不同,比如在平面几何中,一般代表纵坐标,给定一个确定x,必然会有一个确定的纵坐标,这其实就是一个准确的定义,同样在实际问题,同样需要准确的定义:比如在反转链表中我可以定义:f(n)将有n个节点的链表反转,那么f(n-1)为将有n-1个节点的链表反转。 接下来定义函数 首先:我要建立一个函数 它要去反转一个链表,同时返回反转后链表的头节点; 代码如下:
2.2寻找递归结束条件第二要素:寻找递归结束条件 寻找递归的结束条件:这里引用一段对迭代过程进行控制的过程,同样适用于寻找递归的结束条件:“在什么时候结束迭代过程?这是编写迭代程序必须考虑的问题。不能让迭代过程无休止地重复执行下去。迭代过程的控制通常可分为两种情况:一种是所需的迭代次数是个确定的值,可以计算出来;另一种是所需的迭代次数无法确定。对于前一种情况,可以构建一个固定次数的循环来实现对迭代过程的控制;对于后一种情况,需要进一步分析出用来结束迭代过程的条件” 递归的结束条件同样适用; 结束条件的作用是什么:举个通俗的例子,比如有这样一个故事: 从前有座山,山里有个庙,庙里有个老和尚,老和尚给小和尚讲故事,讲的是: 从前有座山,山里有个庙,庙里有个老和尚,老和尚给小和尚讲故事,讲的是: 从前有座山,山里有个庙,庙里有个老和尚,老和尚给小和尚讲故事,讲的是: . . . 如果没有结束条件那么这个“故事”会无限的进行下去,但是程序在执行过程中内存是有限的,所以程序就会报错。 那么我们可以设定一个结束条件:比如,当小和尚睡着了(太烦了),老和尚就停止讲故事。 同样在递归中我们也加入一个调节用以结束递归过程,而且可以采用迭代过程控制的思想,那么反转链表过程中,我们无法确定递归的次数,那么我们仔细分析,发现当头节点所指向的下一个结点为NULL时递归结束,同时需要保护当传入参数时为NULL时直接返回 代码如下(示例):
2.3找出函数的等价关系式同样的我们可以借用迭代关系中的方法,“所谓迭代关系式,指如何从变量的前一个值推出其下一个值的公式(或关系)。迭代关系式的建立是解决迭代问题的关键,通常可以使用递推或倒推的方法来完成”递归关系式也同样如此; 分析:如果我们要将有10个节点的链表反转,那么我们只需要将9个节点反转,再将第二个节点第一个节点反转;而想要将9个节点反转,只要将9个节点中剩余的8个节点反转,再将9个节点中的第一个节点和第二个节点反转即可;而要反转8个节点,只需要将剩余的7个节点反转,再将9个节点中的第一个节点和第二个节点反转即可;以此类推,直到结束调节; 因此,可以得到递推关系: 想要反转n个节点的链表,只需将剩余的n-1个节点反转,然后将第二个节点和第一个节点反转即可
三、效率问题以上就是一个动态规划三个要素的实现过程,开头我们说过,递归比较好理解但是很有可能会带来效率问题,因为我们会不断的计算重复重叠的子问题,具体我以后会开一篇文章新讲,这里我简单的提一下,我曾经遇到这样一道题,很多人应该也见过,这个问题叫做“盒中取球”,它的题目是这样的:今盒子里有n个小球,A、B两人轮流从盒中取球,每个人都可以看到另一个人取了多少个, 实现函数当A赢时输出1,A输时输出0;这其实是一道动态规划的题,但是我用递归试了一下,当输出较大的数(初始球数)时,输出结果需要相当的时间,代码如下:有兴趣的同学可以输入60到80之间的数试试,
总结递归并没有想象中的难,其实相对比较容易,只要记住它的三要素,”哲学三问“,并且准确执行,多多练习,慢慢就会理解,多练习是理解一个概念最好的方式,书读百遍其意自现,代码也是,理解递归后面对于动态规划也会更好的理解,新手刚开始写博客,欢迎评论指出错误。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
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 0:55:28- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |