【函数递归调用】递归调用经典问题—汉诺塔问题
1.函数的递归调用
函数可以直接或者间接的调用其自身,这称为函数的递归调用。递归算法的实质是将原有的问题逐层拆解为新的问题,而解决新的问题又用到了原问题的解法,因此可以继续调用自身分解,按照此原则一直分解下去,每次出现的新问题都是原有问题的子集(或者说是简化版的原问题),而最终的最终分解出来的最后一个问题,一定是已知解的问题,否则没有意义。
因此递归过程都可以用以下两个阶段概括。
Step1:递推。所谓递推就是将原有的问题不断拆解为新的子问题,其子问题就是原有问题的弱化(或者说更少层)的问题,这样,逐渐从未知向已知推进,最终的一个子问题一定是个已知的问题,到达此后,递归阶段结束。
Step2:回归。上一阶段递归阶段结束后,进入回归阶段,所谓回归就是从上一阶段的已知的问题出发,按照递推的过程,逐一求值回归,逐渐将未知问题都变成已知问题,一直到达递推的最开始处,结束回归阶段,问题解决。
2.经典递归调用—汉诺塔问题
2.1 问题描述
有三根针A,B, C。A针上有n个盘子,盘子大小不等,大的在下,小的在上,如下图示,要把这n个盘子从A针移动到C针,在这个过程中可以借助B针,每次只允许动一个盘子,而且在移动的过程中,这三根针上都保持大盘子在下,小盘子在上。
![](/assets/blank.gif)
2.2 解决思路
实际上,正如上面所说,这是一个典型的递归调用。要解决这个问题,本质上还是以上所说的递归的两个阶段。
Step1:递归
①:从问题出发,我们需要达到的目标是什么:我们是想要将A上的n个盘子移动到C上
②:为了解决①,我们可以这么做:
(2.1)我们可以把n-1个盘子从A针(1至n-1号盘)移至B针;
(2.2)之后将A针中剩下的第n号盘(最下面那个)移至C针;
(2.3)最后我们再把第2.1步中那n-1个盘子从B针全部移回至C针,至此,C针上有n个盘子,问题解决。
经过以上三个步骤,我们把想要解决的目标问题拆分成了3个新的子问题,且这3个新的子问题都是原有的问题的弱化版或者说低层版本,我们只需要按照此一直递归,最后找到一个已知的问题即可,下面我们继续递归。
③:
针对问题2.1,也就是将n-1个盘子从A针移动到B针,这个问题熟悉不熟悉?没错,这个问题他不就是我们要解决的问题(从A->C移动n个盘子)换了个目标盘(变成了从A->B)还有减少了一次次数(移动n-1个盘子)的弱化版本么?所以这个问题本身又可拆分成3个新的子问题,现在我们的目标是:我们是想要将A上的n-1个盘子移动到B上。为了解决这个问题,我们可以这么做:
(3.1)我们可以把n-2个盘子A针(1至n-2号盘)移至C针;
(3.2)之后将A针中剩下的第n-1号盘(最下面那个)移至B针;
(3.3)最后我们再把第3.1步中那n-2个盘子从C针全部移回至B针,至此,B针上有n-1个盘子,问题解决。
经过以上3个步骤,问题进一步弱化了,如3.1所示,需要把n-2个盘子A针(1至n-2号盘)移至C针,我们只需要移动n-2个盘子即可。这个问题熟悉不熟悉?没错,这就是我们要解决的问题(从A->C移动n个盘子),次数减少了两次次数(移动n-2个盘子)的进一步弱化版本么?看到这里相信你已经找到了规律。
所以,要解决问题3.1我们可以进一步拆分成3个新的子问题,如此反复,就是一个Step1不断递推的过程,直到最后问题被拆分为:需要移动1个盘子从起始针->目标针,此时直接移动即可。这也就是所谓的递推的最后即最终的子问题变成了一个已知问题,递推阶段便结束了。
递推阶段结束后,便是逐层回归,从已知问题出发,每个n.1问题解决后,顺序解决n.2,n.3,直到回到最开始处,结束回归。比如上述3.1解决后,3.2可直接移动,3.3又可拆分成3个新的子问题,一直拆分到出现已知问题,层层回归解决3.3问题。
我们是为了解决2.1问题才拆分成3.1,3.2,3.3问题,那么3.1,3.2,3.3问题都解决后,也就是2.1问题被解决了,继续解决2.2问题,2.2问题可直接移动,问题解决。继续解决2.3问题,还是不断递归拆分直到出现已知问题,再不断回归解决问题2.3.
我们是为了解决我们最初的1问题也就是最初的目标问题才拆分成2.1,2.2,2.3问题的,因此,2.1,2.2,2.3问题都解决后,最初的1问题也就解决了。至此全部结束。
2.3 C++代码编写
代码写起来很简单,首先定义一个最基本的操作:移动盘子
从A移动一个盘子到C,起始针A称为src原盘,终点盘C称为dst目标盘,那么便有:
//移动src最上面一个盘子到dst针void move(char src, char dst){cout << src << "--》" << dst << endl; //表示将src的一个盘子移动到了dst盘}
接下来我们再定义一个函数:从原盘移动n个盘子到目标盘
起始针称为src原盘,借助中间盘称为medium中间盘,终点盘称为dst目标盘,那么便有:
//代表从src->dst(借助medium)移动n个盘子void hanoi(int n,char src,char medium,char dest)
知道以上代表的含义后,我们就可以开始编写代码解决问题了。
经过2.2章节的分析我们知道,要解决①问题,我们拆分成了3个子问题2.1,2.2,2.3,我们分别看下这三个子问题:
目标问题:将n个盘子从A针移到C针
分解步骤1:我们先把n-1个盘子从A针(1至n-1号盘)移至B针(借助C针);
这个问题写成代码就是:
//将n-1个盘子从A针(借助C针)移动到B针上hanoi(int n-1,A,C,B);
因为刚开始传入参数时候,赋值的A是src针,B是medium针,C是dst针,所以可以写成:
//将n-1个盘子从A针(借助C针)移动到B针上hanoi(int n-1,src,dst,medium);
分解步骤2:之后将A针中剩下的第n号盘(最下面那个)移至C针;
这个问题写成代码就是:
//将A针中剩下的第n号盘(最下面那个)移至C针move(A,C);
因为刚开始传入参数时候,赋值的A是src针,C是dst针,所以可以写成:
//将A针中剩下的第n号盘(最下面那个)移至C针move(src,dst);
分解步骤3:最后我们再把那n-1个盘子从B针全部移至C针(借助A针);
这个问题写成代码就是:
//将n-1个盘子从B针(借助A针)移动到C针上hanoi(int n-1,B,A,C);
因为刚开始传入参数时候,赋值的A是src针,B是medium针,C是dst针,所以可以写成:
//将n-1个盘子从B针(借助A针)移动到C针上hanoi(int n-1,medium,src,dst);
当最终n=1时,我们只需要移动move(src,dst)即可,这也是最终的已知问题。
因此,完整的代码为:
void move(char src, char dst){cout << src << "--》" << dst << endl;}void hanoi(int n, char src, char medium, char dst){if (n==1) //n==1代表最终的已知问题{move(src, dst);}else{hanoi(n - 1, src, dst, medium); //子问题2.1,继续调用自身move(src, dst); //子问题2.2hanoi(n - 1, medium, src, dst); //子问题2.3,继续调用自身}}int Exam_3_10(){int n;cout << "请输入盘子个数:" << endl;cin >> n;hanoi(n, 'A', 'B', 'C');return 0;}
2.4 3层汉诺塔动画演示
举个简单的例子,假设A上有3个盘子1,2,3盘,也就是3层汉诺塔问题。
目标问题:我们需要将3个盘子从A针移动到C针(借助B)
分解问题:
(2.1)我们可以先把2个盘子从A针(1、2号盘)移至B针;
(2.2)之后将A针中剩下的第3号盘移至C针;
(2.3)最后我们再把第2.1步中那2个盘子从B针全部移回至C针,至此,C针上有3个盘子,问题解决。
步骤如图所示:
![](/assets/blank.gif)
![](/assets/blank.gif)
![](/assets/blank.gif)
具体细分到每一步的Gif动画演示如下:
![](/assets/blank.gif)
【函数递归调用】递归调用经典问题—汉诺塔问题相关推荐
- Python入门之经典函数实例——第1关:递归函数 - 汉诺塔的魅力
任务描述 在Python函数内部,我们可以去调用其他函数.所以如果一个函数在内部调用自身,这个函数我们就称为递归函数.本关我们将以汉诺塔的例子来感受递归函数的方法与应用. 汉诺塔问题源于印度一个古老传 ...
- 【Java数据结构与算法】第十七章 二分查找(非递归)和分治算法(汉诺塔)
第十七章 二分查找(非递归)和分治算法(汉诺塔) 文章目录 第十七章 二分查找(非递归)和分治算法(汉诺塔) 一.二分查找 1.思路 2.代码实现 二.分治算法(汉诺塔) 1.概述 2.汉诺塔 一.二 ...
- 【Python】函数递归实例之字符串反转、汉诺塔问题分析
递归的定义 函数定义中调用函数自身的方式 两个特性: 链条:计算过程存在递归链条 例如,n!=n*(n-1)!,n!与(n-1)!就构成了递归链条 基例:基础的实例,存在一个或多个不需要再次递归的基例 ...
- 递归经典例题 --- 汉诺塔(图文详解)
目录 一.介绍 二.游戏规则 三.玩法简介 四.算法分析 五.代码解析 六.源码 七.递归过程详解 一.介绍 汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具.大梵 ...
- 汉诺塔python创新设计_递归经典案例汉诺塔 python实现
最近在廖雪峰大神的教程学习python 学到递归的时候有个汉诺塔的练习,汉诺塔应该是学习计算机递归算法的经典入门案例了,因此本人以为能够写篇博客来表达一下本身的看法.这markdown编辑器还不怎么会 ...
- 递归:这帮小兔子崽子、汉诺塔游戏+习题复习
##坑爹的兔子 ##斐波那契数列的迭代实现 ※我们都知道兔子繁殖能力是惊人的,如下图: ※我们可以用数学函数来定义: ※课间练习:假设 ...
- 要理解递归,得先理解递归--用Java语言由浅入深讲解汉诺塔游戏
2019独角兽企业重金招聘Python工程师标准>>> 一.递归是什么? 定义:程序调用自身的编程技巧称为递归.它分为调用阶段和回退阶段,递归的回退顺序是它调用顺序的逆序. 递归使用 ...
- 汉诺塔递归python搬运次数_Python3.x | 汉诺塔递归理解
在刚学廖雪峰廖大佬的python3教程中的递归时,前面的内容理解都觉得还行,到了做汉诺塔的练习时会觉得有些发懵,后面多看几遍和练习后也就理解了. 因为遇到有人在问这个问题咋理解,因此写下我的想法,希望 ...
- python汉诺塔递归并统计次数_Python之汉诺塔递归运算
汉诺塔问题是一个经典的问题.汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆 ...
最新文章
- ArrayList、linklist、list的区别
- python类型提示模块包_(任何)python模块的类型提示是什么?
- 破解前端面试系列(3):如何搞定纸上代码环节?
- 记-php连接mssql遇上的问题
- 树莓派安装ArchLinux
- leetcode10. 正则表达式匹配 一道没有解释的字符串dp困难题
- 产品经理和程序员的黑话
- 条件语句的多层嵌套问题优化,助你写出不让同事吐槽的代码
- 链上体育和游戏平台Rage.Fan完成160万美元私募轮融资
- python multiprocessing遇到Can’t pickle instancemethod问题
- 数字电子技术基础阎石老师第五版课后习题解答-很抱歉,其实才写了两道题,大家不要误点进来耽误时间了。但是开始写了又不想删掉,希望日后能补起来吧。
- 使用C++刷算法题的简明教程
- JS睡眠sleep()
- 多少人,一边疯狂跳槽,一边疯狂后悔
- 判断线程池任务执行完成
- 录屏软件哪个好?电脑录屏软件排行榜推荐
- OpenStack安装Placement组件部署(四)
- 一步一步学网络爬虫(从python到scrapy)
- SPM提取大脑surface
- adf4360的寄存器写入顺序
热门文章
- Go语言 闭包的最佳实践 (Golang经典编程案例)
- 如何让开关打开_【Aqara智能开关D1系列体验】多场景探索:墙壁智能开关+智能灯=?...
- ubuntu18.04下的mysql创建表
- ise 时钟约束_ISE——ucf文件中时序约束
- Navicat Premium 12连接MongoDB不显示系统库
- java criteria创建_Java hibernate如何创建一个Criteria对象?
- XML期末练习题及答案
- 用Ubuntu破解wep无线加密
- JAVA实现视频加密
- c语言程序设计 华农,华南农业大学C语言程序设计实验指导书参考答案