采用递归和非递归方法求解Hanoi问题
时间:2020-04-10
本文章向大家介绍采用递归和非递归方法求解Hanoi问题,主要包括采用递归和非递归方法求解Hanoi问题使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
目的:领会基本递归算法设计和递归到非递归的转换方法
内容:编写一个程序exp5-1.cpp,采用递归和非递归方法求解Hanoi问题,输出三个盘片的移动过程
写在前面
题目是昨天老师发在学习通上的,目前
解决了:
- Hanoi问题理解
- Hanoi递归算法及其实现
未解决的:
- Hanoi非递归算法及实现
(PPT上是用栈来实现的,然而笔者对栈不熟...解决完再记上来吧)
以下就从解决了的两个方面展开讨论
Hanoi问题理解
笔者参考的是算法动态图解app上的解释,还挺直观的:
简单来说就是有X,Y,Z三个柱子,目标是将X柱子上的盘片移动到Y柱子上,同时要保持和X柱相同的顺序。X柱子上盘片自下而上、由大到小放置着n个盘片,两个要求:
Ⅰ. 一次只能移一个盘片
Ⅱ.不能把大盘片放在小盘片上
个人的理解:
首先,为了方便分析,将X柱上盘片自上而下依次编号为\(1,2...n\)
- 当n=1时,即A柱上只有一个盘片,直接从X移动到Z,这是最简单的情况
- 当n=2 时,
第一步,把1号移动到Y柱(因为要满足要求Ⅱ,2号盘片必须第一个移动到Z柱上,那么必须把1号先移开,移动到哪里?肯定不能是Z柱,那么就是Y柱了)
第二步,把2号盘移到Z柱
第三步,把1号从Y柱移动到Z柱,完成! - 当n=3时,
第一步,可以把1号,2号盘,通过Z柱移到Y柱,这在前面(n=2时)已经证明可行。
第二步,把3号盘移到Y柱
第三步,发现问题转化为n=2的情况,即把1号,2号盘,从Y柱移动到Z柱,方法参见n=2,不再赘述
写到这里,我们发现这个问题是可递归的,n个盘片的Hanoi问题可以通过n-1个盘片的Hanoi问题求得,抽象成数学语言就是$$f(n)=g(f(n-1),c_{n-1}),f(1)=m_1$$
要求\(f(n)\),可先求\(f(n-1),f(n-2)...\),层层递归,直到\(f(1)\)
Hanoi递归算法及其实现
递归模型及递归算法
- 设计递归模型
可以看出递归模型分为递归体,递归出口两个部分,其实就是高中数学数列,递归函数概念 - 设计递归算法(以本题为例)
把盘片数,X柱,Y柱,Z柱分别抽象成自定义函数的四个参数n,X,Y,Z
void Hanoi1(int n,char X,char Y,char Z)
分别用if语句,else语句描述递归出口与递归体
- 算法代码:
//递归法
void Hanoi1(int n,char X,char Y,char Z){
if(n==1){
printf("\t将第%d个盘片从%c移动到%c\n",n,X,Z);//递归出口,当只有一个盘片时 }
else {
Hanoi1 (n-1,X,Z,Y);//将n-1个盘片,通过z,从x移动到y
printf ("\t把第%d个盘片从%c移动到%c\n",n,X,Z);//将第n个盘片,从x移动到z
Hanoi1 (n-1,Y,X,Z);//将n-1个盘片,通过x,从y移动到z
}
}
Hanoi递归算法的实现
理解了算法代码的实现,接下来就就是"搬砖"阶段了
在main()函数里分别初始化三个参数的值,然后调用Hanoi1()就可以了
完整代码:
#include <iostream>
using namespace std;
//递归法
void Hanoi1(int n,char X,char Y,char Z){
if(n==1){
printf("\t将第%d个盘片从%c移动到%c\n",n,X,Z);//递归出口,当只有一个盘片时
}
else {
Hanoi1 (n-1,X,Z,Y);//将n-1个盘片,通过z,从x移动到y
printf ("\t把第%d个盘片从%c移动到%c\n",n,X,Z);//将第n个盘片,从x移动到z
Hanoi1 (n-1,Y,X,Z);//将n-1个盘片,通过x,从y移动到z
}
}
int main() {
int n=3;
char X='x',Y='y',Z='z';
cout <<"递归法过程:"<<endl;
Hanoi1 (n,X,Y,Z);
return 0;
}
运行截图:
写在最后
在"搬砖"的过程中,出现了许多错误,变量未初始化(uninitialzing),函数未指名(not declared) ...原因在于没有经历完整的c语言编程过程,只是看教材的代码,效率确实太低了。
原文地址:https://www.cnblogs.com/hzyb2018/p/12672049.html
- Spring Cloud Edgware新特性之三:使用配置属性自定义Feign的行为
- 碎片化 | 第四阶段-43-struts2拦截器interceptor-视频
- Spring Cloud Edgware新特性之二:如何配置Zuul的Hystrix线程池
- 碎片化 | 第四阶段-44-struts2注解使用-视频
- Spring Cloud Edgware新特性之:解决Eureka中Jersey 1.x版本过旧的问题-不使用Jersey
- 如何自定义微服务的Instance ID
- 怎样做情感分析
- Python|编写自己的类
- 碎片化 | 第四阶段-45-session为空问题解决-视频
- 以后有机会写框架用得着的
- 合并两个不相关的Git仓库
- 用 Tensorflow 建立 CNN
- 碎片化 | 第四阶段-36-struts-spring结合jdbc实现删除功能-视频
- 跨域访问支持(Spring Boot、Nginx、浏览器)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Windows10安装linux子系统的两种方式(图文详解)
- Android 图片处理避免出现oom的方法详解
- session登陆成功第四篇4
- Android编程使用pull方式解析xml格式文件的方法详解
- Android中ActionBar和ToolBar添加返回箭头的实例代码
- Android自定义双向进度条的实现代码
- android视频截屏&手机录屏实现代码
- Android自定义组件跟随自己手指主动画圆
- Android RecyclerView 实现快速滚动的示例代码
- Android的八种对话框的实现代码示例
- Android使用RecyclerView实现今日头条频道管理功能
- Liunx(centos8)下的yum的基本用法和实例(推荐)
- Android中LeakCanary检测内存泄漏的方法
- Linux 查看磁盘IO并找出占用IO读写很高的进程
- Android实现简单的拨号器功能