目的:领会基本递归算法设计和递归到非递归的转换方法
内容:编写一个程序exp5-1.cpp,采用递归和非递归方法求解Hanoi问题,输出三个盘片的移动过程
写在前面
题目是昨天老师发在学习通上的,目前
解决了:
- Hanoi问题理解
- Hanoi递归算法及其实现
未解决的:
- Hanoi非递归算法及实现
(PPT上是用栈来实现的,然而笔者对栈不熟...解决完再记上来吧)
以下就从解决了的两个方面展开讨论
Hanoi问题理解
笔者参考的是算法动态图解app上的解释,还挺直观的:
简单来说就是有X,Y,Z三个柱子,目标是将X柱子上的盘片移动到Y柱子上,同时要保持和X柱相同的顺序。X柱子上盘片自下而上、由大到小放置着n个盘片,两个要求:
Ⅰ. 一次只能移一个盘片
Ⅱ.不能把大盘片放在小盘片上
个人的理解:
首先,为了方便分析,将X柱上盘片自上而下依次编号为\(1,2...n\)
- 当n=1时,即X柱上只有一个盘片,直接从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语言编程过程,只是看教材的代码,效率确实太低了。