1.函数的递归调用

函数可以直接或者间接的调用其自身,这称为函数的递归调用。递归算法的实质是将原有的问题逐层拆解为新的问题,而解决新的问题又用到了原问题的解法,因此可以继续调用自身分解,按照此原则一直分解下去,每次出现的新问题都是原有问题的子集(或者说是简化版的原问题),而最终的最终分解出来的最后一个问题,一定是已知解的问题,否则没有意义。

因此递归过程都可以用以下两个阶段概括。

Step1:递推。所谓递推就是将原有的问题不断拆解为新的子问题,其子问题就是原有问题的弱化(或者说更少层)的问题,这样,逐渐从未知向已知推进,最终的一个子问题一定是个已知的问题,到达此后,递归阶段结束。

Step2:回归。上一阶段递归阶段结束后,进入回归阶段,所谓回归就是从上一阶段的已知的问题出发,按照递推的过程,逐一求值回归,逐渐将未知问题都变成已知问题,一直到达递推的最开始处,结束回归阶段,问题解决。

2.经典递归调用—汉诺塔问题

2.1 问题描述

有三根针A,B, C。A针上有n个盘子,盘子大小不等,大的在下,小的在上,如下图示,要把这n个盘子从A针移动到C针,在这个过程中可以借助B针,每次只允许动一个盘子,而且在移动的过程中,这三根针上都保持大盘子在下,小盘子在上。

图2-1 汉诺塔问题示意图

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个盘子,问题解决。

步骤如图所示:

步骤2.1- 先把2个盘子从A移动到B

步骤2.2- 把A上的最后一个盘子移动到C

步骤2.3- 把B上的2个盘子移回C

具体细分到每一步的Gif动画演示如下:

三层汉诺塔动画演示

【函数递归调用】递归调用经典问题—汉诺塔问题相关推荐

  1. Python入门之经典函数实例——第1关:递归函数 - 汉诺塔的魅力

    任务描述 在Python函数内部,我们可以去调用其他函数.所以如果一个函数在内部调用自身,这个函数我们就称为递归函数.本关我们将以汉诺塔的例子来感受递归函数的方法与应用. 汉诺塔问题源于印度一个古老传 ...

  2. 【Java数据结构与算法】第十七章 二分查找(非递归)和分治算法(汉诺塔)

    第十七章 二分查找(非递归)和分治算法(汉诺塔) 文章目录 第十七章 二分查找(非递归)和分治算法(汉诺塔) 一.二分查找 1.思路 2.代码实现 二.分治算法(汉诺塔) 1.概述 2.汉诺塔 一.二 ...

  3. 【Python】函数递归实例之字符串反转、汉诺塔问题分析

    递归的定义 函数定义中调用函数自身的方式 两个特性: 链条:计算过程存在递归链条 例如,n!=n*(n-1)!,n!与(n-1)!就构成了递归链条 基例:基础的实例,存在一个或多个不需要再次递归的基例 ...

  4. 递归经典例题 --- 汉诺塔(图文详解)

    目录 一.介绍 二.游戏规则 三.玩法简介 四.算法分析 五.代码解析 六.源码 七.递归过程详解 一.介绍 汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具.大梵 ...

  5. 汉诺塔python创新设计_递归经典案例汉诺塔 python实现

    最近在廖雪峰大神的教程学习python 学到递归的时候有个汉诺塔的练习,汉诺塔应该是学习计算机递归算法的经典入门案例了,因此本人以为能够写篇博客来表达一下本身的看法.这markdown编辑器还不怎么会 ...

  6. 递归:这帮小兔子崽子、汉诺塔游戏+习题复习

    ##坑爹的兔子 ##斐波那契数列的迭代实现            ※我们都知道兔子繁殖能力是惊人的,如下图:            ※我们可以用数学函数来定义:            ※课间练习:假设 ...

  7. 要理解递归,得先理解递归--用Java语言由浅入深讲解汉诺塔游戏

    2019独角兽企业重金招聘Python工程师标准>>> 一.递归是什么? 定义:程序调用自身的编程技巧称为递归.它分为调用阶段和回退阶段,递归的回退顺序是它调用顺序的逆序. 递归使用 ...

  8. 汉诺塔递归python搬运次数_Python3.x | 汉诺塔递归理解

    在刚学廖雪峰廖大佬的python3教程中的递归时,前面的内容理解都觉得还行,到了做汉诺塔的练习时会觉得有些发懵,后面多看几遍和练习后也就理解了. 因为遇到有人在问这个问题咋理解,因此写下我的想法,希望 ...

  9. python汉诺塔递归并统计次数_Python之汉诺塔递归运算

    汉诺塔问题是一个经典的问题.汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆 ...

最新文章

  1. ArrayList、linklist、list的区别
  2. python类型提示模块包_(任何)python模块的类型提示是什么?
  3. 破解前端面试系列(3):如何搞定纸上代码环节?
  4. 记-php连接mssql遇上的问题
  5. 树莓派安装ArchLinux
  6. leetcode10. 正则表达式匹配 一道没有解释的字符串dp困难题
  7. 产品经理和程序员的黑话
  8. 条件语句的多层嵌套问题优化,助你写出不让同事吐槽的代码
  9. 链上体育和游戏平台Rage.Fan完成160万美元私募轮融资
  10. python multiprocessing遇到Can’t pickle instancemethod问题
  11. 数字电子技术基础阎石老师第五版课后习题解答-很抱歉,其实才写了两道题,大家不要误点进来耽误时间了。但是开始写了又不想删掉,希望日后能补起来吧。
  12. 使用C++刷算法题的简明教程
  13. JS睡眠sleep()
  14. 多少人,一边疯狂跳槽,一边疯狂后悔
  15. 判断线程池任务执行完成
  16. 录屏软件哪个好?电脑录屏软件排行榜推荐
  17. OpenStack安装Placement组件部署(四)
  18. 一步一步学网络爬虫(从python到scrapy)
  19. SPM提取大脑surface
  20. adf4360的寄存器写入顺序

热门文章

  1. Go语言 闭包的最佳实践 (Golang经典编程案例)
  2. 如何让开关打开_【Aqara智能开关D1系列体验】多场景探索:墙壁智能开关+智能灯=?...
  3. ubuntu18.04下的mysql创建表
  4. ise 时钟约束_ISE——ucf文件中时序约束
  5. Navicat Premium 12连接MongoDB不显示系统库
  6. java criteria创建_Java hibernate如何创建一个Criteria对象?
  7. XML期末练习题及答案
  8. 用Ubuntu破解wep无线加密
  9. JAVA实现视频加密
  10. c语言程序设计 华农,华南农业大学C语言程序设计实验指导书参考答案