一文读懂递归算法

2019 年 7 月 18 日 算法与数据结构

作者:刘毅

来自:https://www.61mon.com/index.php/archives/208/


递归的学习绝对是一个持久战,没有人可以一蹴而就。一年两年的,很寻常。

问题的复杂,加上递归本身的细节,我们想要 "学会","学好",再 "用好",是需要一个漫长的过程的。所以还希望读者有足够的耐心。


一:什么是递归


所谓递归,简单点来说,就是一个函数直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。

我们可以把” 递归 “比喻成 “查字典 “,当你查一个词,发现这个词的解释中某个词仍然不懂,于是你开始查这第二个词。

可惜,第二个词里仍然有不懂的词,于是查第三个词,这样查下去,直到有一个词的解释是你完全能看懂的,那么递归走到了尽头,然后你开始后退,逐个明白之前查过的每一个词,最终,你明白了最开始那个词的意思。(摘自知乎的一个回答)

我们以阶乘作为:

int Factorial(int n){    

      if (n == 0)  return 1;  

      return

      n * Factorial(n - 1);

}


二:递归与栈的关系


常常听到 “递归的过程就是出入栈的过程”,这句话怎么理解?我们以上述代码为例,取  n = 3 ,则过程如下:

  • 第 1~4 步,都是入栈过程,Factorial(3)调用了Factorial(2)Factorial(2)又接着调用Factorial(1),直到Factorial(0)

  • 第 5 步,因 0 是递归结束条件,故不再入栈,此时栈高度为 4,即为我们平时所说的递归深度;

  • 第 6~9 步,Factorial(0)做完,出栈,而Factorial(0)做完意味着Factorial(1)也做完,同样进行出栈,重复下去,直到所有的都出栈完毕,递归结束。

每一个递归程序都可以把它改写为非递归版本。我们只需利用栈,通过入栈和出栈两个操作就可以模拟递归的过程,二叉树的遍历无疑是这方面的代表。

但是并不是每个递归程序都是那么容易被改写为非递归的。某些递归程序比较复杂,其入栈和出栈非常繁琐,给编码带来了很大难度,而且易读性极差,所以条件允许的情况下,推荐使用递归。


三:如何思考递归


在初学递归的时候, 看到一个递归实现, 我们总是难免陷入不停的验证之中,比如上面提及的阶乘,求解Factorial(n)时,我们总会情不自禁的发问,Factorial(n-1)可以求出正确的答案么?接着我们就会再用Factorial(n-2)去验证,,,不停地往下验证直到Factorial(0)

对递归这样的不适应,和我们平时习惯的思维方式有关。我们习惯的思维是:已知Factorial(0),乘上 1 就等于Factorial(1),再乘以 2 就等于Factorial(2),,,直到乘到 n。

而递归和我们的思维方式正好相反。

那我们怎么判断这个递归计算是否是正确的呢?Paul Graham 提到一种方法,如下:

如果下面这两点是成立的,我们就知道这个递归对于所有的 n 都是正确的。

  1. 当  n = 0 , 1  时,结果正确;

  2. 假设递归对于  n 是正确的,同时对于  n + 1  也正确。

这种方法很像数学归纳法,也是递归正确的思考方式,上述的第 1 点称为基本情况,第 2 点称为通用情况。

在递归中,我们通常把第 1 点称为终止条件,因为这样更容易理解,其作用就是终止递归,防止递归无限地运行下去。

下面我们用两个例子来具体说明这种数学归纳法:

例 1 汉诺塔展开目录

问题描述为:有三根杆子 A,B,C。A 杆上有 N 个穿孔圆盘,盘的尺寸由上到下依次变大,B,C 杆为空。要求按下列规则将所有圆盘移至 C 杆:

  1. 每次只能移动一个圆盘;

  2. 大盘不能叠在小盘上面。

问:如何移?最少要移动多少次?

首先看下基本情况,即终止条件:N=1 时,直接从 A 移到 C。

再来看下通用情况:当有 N 个圆盘在 A 上,我们已经找到办法将其移到 C 杠上了,我们怎么移动 N+1 个圆盘到 C 杠上呢?很简单,我们首先用将 N 个圆盘移动到 C 上的方法将 N 个圆盘都移动到 B 上,然后再把第 N+1 个圆盘(最后一个)移动到 C 上,再用同样的方法将在 B 杠上的 N 个圆盘移动到 C 上,问题解决。

代码如下:

void Hanoi(int n, char a, char b, char c){    //终止条件

    if (n == 1)

    {

         cout << a << "-->" << c << endl;        

         return;

    }    //通用情况

    Hanoi(n - 1, a, c, b);

    Hanoi(1, a, b, c);

    Hanoi(n - 1, b, a, c);

}

例 2 求二叉树节点个数展开目

首先看下基本情况,即终止条件:当为空树时,节点数为 0;

再来看下通用情况:当前节点的左,右子树节点数都被求出,则以当前结点为根的二叉树的节点总数就是 “左子树 + 右子树 + 1”。

代码如下:

int GetNodes(Node * node){    //终止条件

    if (node == nullptr)

      return 0;    //通用情况

    return

      GetNodes(node->left) + GetNode(node->right) + 1;

}


四:什么时候该用递归


当我们遇到一个问题时,我们是怎么判断该题用递归来解决的?


问题可用递归来解决需具备的条件:

  1. 子问题需与原问题为同样的事,且规模更小;

  2. 程序停止条件。

END


●编号962,输入编号直达本文

●输入m获取文章

程序员数学之美

程序员数学学习

锻炼数学逻辑思维

登录查看更多
0

相关内容

刘毅,国家水电可持续发展研究中心主任、中国水利水电科学研究院水电中心主任、结构所所长、正高级工程师、水利部水工程建设与安全重点实验室主任、中国大坝工程学会副监事长、中国水利学会理事、中国水力发电工程学会理事。长期从事复杂水工结构仿真分析、高坝安全等方面的研究,承担国家重点研发计划项目等40余项课题,高坝仿真、智能温控等多项成果应用于锦屏一级、白鹤滩等数十座混凝土坝工程。曾获国家科技进步二等奖、水利科技英才奖、水电英才奖
【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
192+阅读 · 2020年6月29日
【2020新书】从Excel中学习数据挖掘,223页pdf
专知会员服务
90+阅读 · 2020年6月28日
《强化学习》简介小册,24页pdf
专知会员服务
271+阅读 · 2020年4月19日
【经典书】数据结构与算法C++,第二版,738页pdf
专知会员服务
166+阅读 · 2020年3月27日
专知会员服务
41+阅读 · 2020年2月20日
Transformer文本分类代码
专知会员服务
116+阅读 · 2020年2月3日
GitHub超2.7万星,最全Python入门算法来了
新智元
5+阅读 · 2019年4月28日
《常用算法之智能计算 (四) 》:遗传算法
数盟
4+阅读 · 2018年12月21日
目标跟踪算法分类
算法与数据结构
20+阅读 · 2018年9月28日
从示例中理解SVM算法(附代码)
论智
9+阅读 · 2018年5月10日
图解机器学习的常见算法
机器学习算法与Python学习
5+阅读 · 2018年4月2日
循环神经网络的介绍、代码及实现
AI研习社
3+阅读 · 2017年11月21日
[DLdigest-8] 每日一道算法
深度学习每日摘要
4+阅读 · 2017年11月2日
漫画:什么是Bitmap算法?
算法与数据结构
4+阅读 · 2017年8月6日
人工神经网络算法及其简易R实现
R语言中文社区
18+阅读 · 2017年8月5日
机器学习算法比较
我爱机器学习
4+阅读 · 2016年12月11日
Music Transformer
Arxiv
5+阅读 · 2018年12月12日
Arxiv
3+阅读 · 2018年4月9日
Arxiv
6+阅读 · 2018年1月29日
Arxiv
5+阅读 · 2016年10月24日
VIP会员
相关VIP内容
【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
192+阅读 · 2020年6月29日
【2020新书】从Excel中学习数据挖掘,223页pdf
专知会员服务
90+阅读 · 2020年6月28日
《强化学习》简介小册,24页pdf
专知会员服务
271+阅读 · 2020年4月19日
【经典书】数据结构与算法C++,第二版,738页pdf
专知会员服务
166+阅读 · 2020年3月27日
专知会员服务
41+阅读 · 2020年2月20日
Transformer文本分类代码
专知会员服务
116+阅读 · 2020年2月3日
相关资讯
GitHub超2.7万星,最全Python入门算法来了
新智元
5+阅读 · 2019年4月28日
《常用算法之智能计算 (四) 》:遗传算法
数盟
4+阅读 · 2018年12月21日
目标跟踪算法分类
算法与数据结构
20+阅读 · 2018年9月28日
从示例中理解SVM算法(附代码)
论智
9+阅读 · 2018年5月10日
图解机器学习的常见算法
机器学习算法与Python学习
5+阅读 · 2018年4月2日
循环神经网络的介绍、代码及实现
AI研习社
3+阅读 · 2017年11月21日
[DLdigest-8] 每日一道算法
深度学习每日摘要
4+阅读 · 2017年11月2日
漫画:什么是Bitmap算法?
算法与数据结构
4+阅读 · 2017年8月6日
人工神经网络算法及其简易R实现
R语言中文社区
18+阅读 · 2017年8月5日
机器学习算法比较
我爱机器学习
4+阅读 · 2016年12月11日
Top
微信扫码咨询专知VIP会员