汉诺塔递归与非递归实现

背景介绍

汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

一、汉诺塔的递归实现:

对于汉诺塔的递归实现,我们来这样理解:

  1. 无论如何我们都需要将第n个盘子移动到C柱子上。
  2. 我们什么时候能够取到第n个盘子,必须要把1~n-1个盘子取下来。
  3. 当我们把第n个盘子放到C柱子上后,这时候不就变成了n-1个盘子的汉诺塔了吗?因为无论无何都不会再移动比n大或者相同的盘子号,所以我们只需要将1~n-1个盘子从B柱子移动到C柱子上。
  4. 如果没有盘子,我们就不需要做任何操作。
  5. 当我们需要实现n个盘子的操作,就表示我们必须要实现n-1个盘子的操作;当我们需要实现n-1个盘子的操作,就表示我们必须要实现n-2个盘子的操作…

综上所述,我们来想象一个函数,它能够完成n个盘子的汉诺塔。这样子的话我们也可以借助这个想象的函数来实现n-1个盘子的汉诺塔。那么这个函数的结构我们很容易想到:

 //表示将n个盘子的汉诺塔从origin开始经过pass到达destination的伪代码:
void func(n, origin, pass, destination){if(n == 0){ return; }                 // 终止条件。func(n-1, origin, destination, pass); // 首先将n-1个盘子借助C柱移动到B柱上。move(n, origin, destination)          // 移动第n个盘子。func(n-1, pass, origin, destination); // 最后将n-1个盘子借助B柱移动到C柱上。return;
}

代码如下:

# 源代码
#include <cstdio>
#include <stack>
#include <cmath>using namespace std;void reHanoi(int, char, char, char);int main(){int n;printf("please input the number of Hanoi: ");scanf("%d", &n);reHanoi(n, 'A', 'B', 'C');return 0;
}void reHanoi(int n, char from, char pass, char to){ //汉诺塔的递归实现if(n == 0){ return; }reHanoi(n-1, from, to, pass); // 首先将n-1个盘子移动到B柱上。printf("%d: %c-->%c\n", n, from, to); // 将第n个盘子移动到C柱上。reHanoi(n-1, pass, from, to); // 最后将n-1个盘子移动到C柱上。return;
}

二、汉诺塔的非递归实现:

1.借助栈实现汉诺塔的非递归形式:
在reHanoi(n-1, from, to, pass)进入递归前,我们需要保留调用现场,将参数入栈,使用新的参数调用reHanoi函数。在此过程中需要一直进行入栈操作,直到参数n ==0为止。对此行为,我们可以用一个循环来模拟。在eHanoi(n-1, pass, from, to)函数前,我们要完成当前最后一个盘子的移动操作,再产生新的参数,跳转到func语句执行;

//伪代码:
func: while (n > 0 || !stack.empty())int i = n;while (i != 0) {push(i);i --;}int curNum= pop();if(curNum == 0){continue;}printfElem(curNum);n = curNum;n --;  push(n);}
# 源代码
#include <cstdio>
#include <stack>
#include <cmath>using namespace std;typedef struct elemHanoi{ //定义汉诺一的结构体int num; //层数即编号char from; //起始位置char pass; //借助位置char to; //终点位置
}elemHanoi;void oneNotReHan(elemHanoi);
elemHanoi getElem(int n, char from, char pass, char to);
void printElem(elemHanoi elem);int main(){int n;printf("please input the number of Hanoi: ");scanf("%d", &n);elemHanoi elem = {n, 'a', 'b', 'c'};oneNotReHan(elem);return 0;
}elemHanoi getElem(int n, char from, char pass, char to){elemHanoi elem = {n, from, pass, to};return elem;
}void printElem(elemHanoi elem){printf("%d from %c throught %c to %c\n", elem.num, elem.from, elem.pass, elem.to);return;
}void oneNotReHan(elemHanoi elem){ //汉诺一塔非递归实现,借助栈(参考树的中序遍历)。elemHanoi tempElem = elem;int number;stack<elemHanoi> myStack;myStack.push(elem);while(tempElem.num > 0 || !myStack.empty()){while(tempElem.num > 0){ //在遍历过程中要判断是否还需要继续往下递归。tempElem = getElem(tempElem.num-1, tempElem.from, tempElem.to, tempElem.pass);myStack.push(tempElem);}if(!myStack.empty()){ //tempElem = myStack.top(); //获取到当前栈顶元素myStack.pop();//如果当前是最终过程的下一个过程(即当前的num=0,表示终止标志),则需要跳过下面步骤。if(tempElem.num == 0){continue;}printf("%d: %c-->%c\n", tempElem.num, tempElem.from, tempElem.to);//创建reHanoi(n-1, pass, from, to)的过程并加入到栈顶。tempElem = getElem(tempElem.num-1, tempElem.pass, tempElem.from, tempElem.to);myStack.push(tempElem);}}return;
}

2.借鉴满二叉树实现汉诺塔的非递归形式:
对于汉诺塔的步骤,我们其实可以看作对一个满二叉树的中序遍历,从上往下分别为第1层(4号盘),第2层(3号盘),第3层(2号盘),第4层(1号盘)。关于本方法的详细介绍请参看文献,链接在文章末尾。

在n=4时我们其实可以明显的看出,第4层(即最下层)满足AB 、BC、CA的循环。
总而言之,奇数层的移动规律为AC、CB、BA , 而偶数层的移动规律为AB 、BC、CA的循环。

#include <cstdio>
#include <stack>
#include <cmath>using namespace std;void twoNotReHan(int n);int main(){int n;printf("please input the number of Hanoi: ");scanf("%d", &n);twoNotReHan(n);return 0;
}//奇数的圆盘的移动规律为AC、CB、BA 的循环。
//序号为偶数的圆盘的移动规律为AB 、BC、CA的循环。
//每一层的移动顺序满足上述要求,从上往下以1开始标记层数, 每一层的模三顺序都是1->0->2->1...。
void twoNotReHan(int n){if(n < 1){return;}int sum = pow(2, n);int index = 1;while(index < sum){int floor = 1;int number = index;while(number%2 == 0){//计算层数保证来得到从下往上数第几层, n-floor+1 就可以的到从上往下的层数。floor+=1;number/=2;}if ((n - floor + 1)%2==1) {//奇数层switch(number%3){case 0: printf("%d: C-->B\n", floor); break;case 1: printf("%d: A-->C\n", floor); break;case 2: printf("%d: B-->A\n", floor); break;}}else{//偶数层switch(number%3){case 0: printf("%d: B-->C\n", floor); break;case 1: printf("%d: A-->B\n", floor); break;case 2: printf("%d: C-->B\n", floor); break;}}index++;}return;
}

1、参考文章:汉诺塔问题的非递归实现
2、参考文献:谭罗生,吴福英,黄明和. Hanoi塔问题的解模型[J]. 计算机应用与软件,2004,21(10):49-51.

汉诺塔递归与非递归实现相关推荐

  1. 【汉诺塔】C语言递归解法,深层次地带你理解汉诺塔公式

    目录 汉诺塔公式 汉诺塔问题在数学层面的公式: C语言递归公式 两层汉诺塔 三层汉诺塔 递归问题可谓是学习C语言以来的第一个拦路虎,而汉诺塔问题更是递归中对新手很不友好的一道经典题,我们接下来从公式角 ...

  2. java实现求解汉诺塔问题(提示, 使用递归)

    实现代码: 求解汉诺塔问题(提示, 使用递归) 汉诺塔问题是一个经典的问题.汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说. 大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从 ...

  3. 个盘子的汉诺塔需要移动几步_图解汉诺塔问题( Java 递归实现)

    汉诺塔简介 最近在看数据结构和算法,遇到了一个非常有意思的问题--汉诺塔问题. 先看下百度百科是怎么定义汉诺塔的规则的: 汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具.大梵天创造世界的时候 ...

  4. 用java编写汉诺塔问题_数据结构与算法之汉诺塔问题(Java递归)

    汉诺塔问题: 有三根柱子,源杆A,暂存杆temp,目的杆C A上有n层盘子,由小到大向下排列,现需要将A杆的盘子移到C杆中 要求:1)大的盘在下面,小的盘在上面 2)一次只能移动一个盘子 个人思路:先 ...

  5. c语言函数汉诺塔不用move,C语言——汉诺塔问题(函数递归)

    问题概述:古代有一个梵塔,塔内有3个座A,B,C.开始时A座上有64个盘子,盘子大小不等,大的在下,小的在上,有一个老和尚想把64个盘子从A座移动到C座,但是规定每次只允许移动一个盘,且在移动过程中在 ...

  6. 经典汉诺塔(Java初学递归篇)

    大一学C的时候已经接触到汉诺塔递归的问题,当时只是简单了解过方法,最近开了算法课,打算重新捋一捋. 题目描述:         有三根柱子分别为A.B.C,柱子A上从下到上按金字塔状叠放着n个不同大小 ...

  7. 借汉诺塔理解栈与递归

    我们先说,在一个函数中,调用另一个函数. 首先,要意识到,函数中的代码和平常所写代码一样,也都是要执行完的,只有执行完代码,或者遇到return,才会停止. 那么,我们在函数中调用函数,执行完了,就会 ...

  8. 由汉诺塔引起的对递归的思考

    对递归的理解在于放弃,放弃对于全程的理解与跟踪,只理解递归两层之间相互的联系,以及递归终结的条件. 汉诺塔永远只有两层,最底层和上层,上层放到中间,底层放好,再把中间的放到底层上面!!! 就这样,在乱 ...

  9. c语言递归汉诺塔次数,c语言递归解决汉诺塔参数变化的疑惑

    c语言递归解决汉诺塔参数变化的疑惑 答案:3  信息版本:手机版 解决时间 2020-04-05 14:20 已解决 2020-04-05 10:49 #include void main() {vo ...

  10. 汉诺塔(Hanoi) ——递归思想

     汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具.传说故事可以点这看. 汉诺塔问题是一个经典的数学难题,由 3 根柱子和多个半径不等的圆盘构成,如下图所示: 汉诺 ...

最新文章

  1. PL/SQL集合类型的整理学习
  2. 智能车竞赛云端比赛第三天:一场在家具建材广场中的智能车比赛
  3. Android开发之发送邮件功能的实现(源代码分享)
  4. 3.1.1 什么是内存?进程的基本原理,深入指令理解其过程
  5. grup2命令启动windows
  6. CF567E President and Roads
  7. 输入法黑科技:语音识别准确率98% 用户超过6亿
  8. mysql用declare会报错_mysql创建存储过程declare 变量时报错
  9. classmethod staticmethod一些领悟
  10. vue添加响应response拦截器,响应登陆超时处理
  11. 分析一个简单的特洛伊木马(虾神写的)
  12. java三国策略手游_策略三国下载-策略三国手游官网版下载-Minecraft中文分享站
  13. 苹果产品信息查询_不知道的细节 苹果官网
  14. MacBook Air下载easyconnect软件后双击打不开后发生的问题
  15. 公式图片转换成Word格式
  16. 如何制作公众号首图?教你一键套用图片模板
  17. C语言——获取键盘方向键效果
  18. TensorFlow2学习七、使用MNIST手写体识别数据集识别自己手写图片
  19. 如何更快地渲染?深入了解3D渲染性能的指南!(5)
  20. 2019考研英语二真题词汇整理

热门文章

  1. 如何在 JavaScript 中清空数组?
  2. 淘宝运营 降低跳失率的方法 优化主图 优化详情页 优化评论
  3. Delphi提取网页中的图片
  4. 重温C语言二:变量学习笔记
  5. 计算机的主要性能指标(计算机组成原理)
  6. 微信小程序 保存图片到相册
  7. Java中的基本数据类型和引用数据类型
  8. 使用adb和cmdline简化Android应用测试
  9. 加拿大访问学者家属如何办理探亲签证?
  10. maya 约束批量导入导出