目 录
目 录 .............................................................. 1 摘 要 ............................................................. 2 一、背景知识 ....................................................... 3 二、问题重述 ....................................................... 3 三、算法分析 ....................................................... 3 四、流程及程序设计 ................................................. 5 (1)、流程图 ...................................................... 5 (2)、模块及其功能介绍 ............................................. 6 五、调试与算法复杂度分析 ........................................... 7 (1)、运行结果 ..................................................... 7 (2)、HANOI塔问题复杂度分析 ....................................... 9 总 结 ........................................................... 10 参考文献 .......................................................... 11 附 录 ............................................................ 12
1
摘 要
汉诺威塔是一款集娱乐与运算的智力游戏,它不仅能使人在休闲的时候放松心情,而且还能在玩的过程中不断的提高你的思维能力.
有三个柱子A, B, C. A柱子上叠放有n个盘子,每个盘子都比它下面的盘子要小一点,可以从上到下用1, 2, 。。。, n编号.要求借助柱子C,把柱子A上的所有的盘子移动到柱子B上.移动条件为:
1、一次只能移一个盘子
2、移动过程中大盘子不能放在小盘子上,只能小盘子放在大盘子上 本文的主要算法是利用函数的递归调用算法。首先,想办法将A座上的前n-1个盘借助C座移动到B座上,然后将A组上的第n个盘移动到C座上。然后再将B座上的n—1个盘借助A座移动到C座上,此次移动也和第一次移动一样,重复递归,直到最后一个盘为止。
关键词:汉诺塔 递归思想 函数调用 数组 指针
2
一、背景知识
汉诺塔(又称河内塔)问题来自中东地区一个古老的传说:在世界刚被创建的时候有一座钻石宝塔(塔A),其上有64个金碟。所有碟子按从大到小的次序从塔底堆放至塔顶。紧挨着这座塔有另外两个钻石宝塔(塔B和塔C)。从世界创始之日起,婆罗门的牧师们就一直在试图把塔A上的碟子移动到塔C上去,其间借助于塔B的帮助。每次只能移动一个碟子,任何时候都不能把一个碟子放在比它小的碟子上面.当牧师们完成任务时,世界末日也就到了。
19世纪的法国大数学家鲁卡曾经研究过这个问题,他正确地指出,要完成这个任务,僧侣们搬动金盘的总次数(把1个金盘从某个塔柱转移到另1个塔柱叫做1次)为:18,446,744,073,709,551,615次。假设僧侣们个个身强力壮,每天24小时不知疲倦地不停工作,而且动作敏捷快速,1秒钟就能移动1个金盘,那么,完成这个任务也得花5800亿年!
二、问题重述
有三个柱子A, B, C。A柱子上叠放有n个盘子,每个盘子都比它下面的盘子要小一点,可以从上到下用1, 2, ..., n编号.要求借助柱子C,把柱子A上的所有的盘子移动到柱子B上.移动条件为:
1、一次只能移一个盘子;
2、移动过程中大盘子不能放在小盘子上,只能小盘子放在大盘子上。 用计算机算法思想解决该问题,利用C++实现其动态演示。
三、算法分析
设A上有n个盘子。
当n=1时,则将圆盘从A直接移动到C。
当n大于等于2时,移动的过程可分解为三个步骤: 第一步 把A上的n—i个圆盘移到B上; 第二步 把A上的一个圆盘移到C上;
第三步 把B上的n—i个圆盘移到C上;其中第一步和第三步是类同的。 为了更清楚地描述算法,用图示法描述如下:
将N个盘子从A杆上借助C杆移动到B杆上。这样移动N个盘子的工作就可以按照以下过程进行:
①第一次调用递归
②将一个盘子从A移动到B上;
3
③第二次调用递归
重复以上过程,直到将全部的盘子移动到位时为止. 由递归算法我们可以得到递推关系: M(n)=2M(n—1)+1 当n〉1时 M(n)=1 当n=1时
4
四、流程及程序设计
(1)、流程图
开始 定义结构体数组M存放盘号和塔座高度 程序初始化 输入要演示的盘块数n n<1||n>10 绘制塔座和盘块 n=10 调用递归函数hanoi( ) n= =1? 调用move( )函数将盘块从A移到C 将前n-1个盘块从A移到B 再将A的第n个盘块移到C 最后将B上的n-1个盘移到C 结 束
有上述流程图得出实现递归函数过程的流程图设计如下图所示:
5
开 始 n= =1? 将前n-1个盘块从A座移到B座 将盘块从A座移到C座 再将A座的第n个盘块移到C座 最后将B座上的n-1个盘块移到C座 结 束
(2)、模块及其功能介绍
首先定义两个类: Tower类(栈)Hanoi类(包含三个Tower类对象组成),程序中大部份功能函数封装在这两个类中(包括:递归算法Hanoi::Move()、图形显示函数Hanoi::Outlin()、移动演示函数Hanoi::MoveShow() 等 ) 塔的盘子是字符串由('=’,’ ’)组成的
另外还有一些函数:Push函数的功能是放入盘子, pop函数的功能是取出盘子 重要函数的分析:
void Move(int n,int A,int B,int C)递归 (这里的A,B,C是相对的,不等同外面定义的A塔,B塔,C塔) {
if(n==1)//递归的终止条件 {
move(A,C);//将A塔上的最后一个盘子盘子直接移动到C塔
}
else{
Move(n-1,A,C,B);//将A塔上的n-1个盘子通过C塔移动到B塔 move(A,C);//将A塔上的最后一个盘子盘子直接移动到C塔 Move(n—1,B,A,C);//将B塔上的n—1个盘子通过A塔移动到C塔 }
}
6
五、调试与算法复杂度分析
(1)、运行结果(以4层Hanoi塔为类) 运行程序得到如下界面:
程序主界面
游戏的初始状态
当完成第一步时,A上第一个盘就移动到B上这时按任意键继续。如下:
7
第一步结束时状态
第二步结束时状态
︰ ︰ ︰
8
第十五步结束的状态
最后就完成了将A上所有的盘子移动到C盘上。 (2)、Hanoi塔问题复杂度分析 ①时间复杂度
程序所花时间正比于所输出的信息行数目,而信息行的数目则等价于盘子的移动次数。考察程序,设盘子移动次数为moves(n),用迭代方法计算公式,得到结果moves(n)=2n—1。因此,hanoi函数的时间复杂度为O(2 n) .
② 空间复杂度
从每个塔上移走盘子时是按照LIFO进行,因此可以把每个塔表示成一个堆栈。3座塔在任何时候总共拥有的盘子都是n个。如果使用链表形式的堆栈,只需申请n个元素所需要的空间.如果使用的是基于公式化描述的堆栈,塔1和塔2的容量都必须是n,而塔3的容量是n-1,因此所需要的空间总数为3n-1.Hanoi塔问题的复杂性是以n为指数的函数,因此在可以接受的范围内,只能解决n值比较小(n<=30)的hanoi问题。对于这个较小的n值,堆栈在空间需求上的差别相当小,可以随意使用。
9
总 结
计算机算法设计与分析和现代计算机技术的实际应用相结合,是我在本阶段学完理论课程之后对自己该方面的能力的一次很好的检验,从开始的算法思路到运行调试后的美观的运行结果界面以及另人兴奋的可用程序,都是一个很好的学习和锻炼的过程。使我们巩固了原有的理论知识,培养了我灵活运用和组合集成所学过知识及技能来分析、解决实际问题的能力.使我体会到自身知识和能力能在实际中的应用和发挥。通过学习我丰富了计算机操作经验,更增强了对 C++语言的使用技巧。
汉诺塔是个不错的数学游戏,由于问题的有趣,所以能很好地提高参与者地热情与兴趣。现在汉诺塔也被运用于很多智力游戏中,我们在玩手机游戏的时候,也会锻炼一下自己的脑力。汉诺塔也很好的体现了数学的递归思想。设计汉诺塔程序,充分了解汉诺塔问题的本质以及怎样移动盘子.认真看课本的方法,还能对平时上课的内容得到巩固和熟练。
10
参考文献
1 严蔚敏。 数据结构(C语言版)。 清华大学出版社. 2007
2 吴乃陵。,况迎辉. C++程序设计(第2版)。 高等教育出版社. 2007 3 王晓东. 计算机算法设计与分析(第三版)。 电子工业出版社. 2007
11
附 录
#include Stack *top; int Top; Tower(int store) { floor=store; if(floor<6)broad=4+2*floor; else broad=2+2*floor; Top=0; string bro; for(int i=0;i〈broad/2;i++) bro=bro+”[]\"; Stack *temp=new Stack; temp—>data=bro; temp—>next=top; top=temp; } 12 string OutFloor(int i) { Stack *toptemp=top; for(int j=0;j〈Top—i;j++) toptemp=toptemp->next; return toptemp—〉data; } void push(string disc) { Stack *temp=new Stack; temp—〉data=disc; temp—>next=top; top=temp; Top++; } string pop() { Stack *temp; string x; if(top==NULL) return NULL; else { x=top-〉data; temp=top; top=top-〉next; free(temp); Top——; return x; } } string disc(int space) { string dis; for(int i=0;i dis=dis+’ ’; for(int j=space;i〈broad-space;i++) dis=dis+'='; for(int k=broad—space;k〈broad;k++) dis=dis+’ '; return dis; } }; class Hanoi { int Store; int broad; Tower *A; Tower *B; Tower *C; int step; int STEP[MAX]; void move(int A,int C) { step++; STEP[step]=A*10+C; } void Move(int n,int A,int B,int C) { if(n==1) move(A,C); else { Move(n-1,A,C,B); move(A,C); 14 Move(n—1,B,A,C); } } public: Hanoi(int store) { Store=store; if(Store〈6)broad=4+2*Store; else broad=2+2*Store; A=new Tower(store); for(int i=1;i<=Store;i++) A—>push(A—>disc(i)); B=new Tower(store); C=new Tower(store); step=0; Move(Store,1,2,3); } void OutStep() { int StepTemp; cout〈<”\\n\移动方法:\"<〈endl; for(StepTemp=1;StepTemp〈=step;StepTemp++) cout<<”\\n\”<<”第\"<〈StepTemp<〈”步:”< } void Outlin() { int i=Store; string space; for(int j=0;j } space=space+” ”; cout<<”\\n\\n\"〈 cout<<\"\”; if(A->Top>=i)cout<〈A-〉OutFloor(i); else cout< else cout〈〈space; cout〈<”\\"; if(C—>Top>=i)cout〈〈C-〉OutFloor(i); else cout< int Step=1; string ans; Outlin(); do { cout〈〈”\\n\第”<〈Step〈〈\"步:\"〈 { case 12: B—〉push(A->pop());break; case 13: C—>push(A->pop());break; 16 case 21: A->push(B—〉pop());break; case 23: C—>push(B-〉pop());break; case 31: A—>push(C—〉pop());break; case 32: B->push(C->pop()); } void GameMove() { int from,go; Outlin(); do{ cout<〈”\\n\请输入移动哪个塔(1,2,3):”; cin>>from; while(from〉3||from〈1) { } cout〈<”\\n\请输入移到哪个塔(1,2,3):\"; cin>〉go; while(go>3||go<1||go==from) { cout<<\"-_-!\"; cin>>go; 17 } Outlin(); if(Step〈step)system(”pause\"); Step++; }while(Step〈=step); cout<<”\\n 演示完毕!(输入任意字符退出)\\n\\n”; cin〉〉ans; cout〈〈\"-_—!”; cin>〉from; } int temp=from*10+go; switch(temp) { case 12: if(A->top—>data〈B->top->data)B—>push(A->pop()); else cout〈〈”ERROR!\"; break; case 13: if(A—〉top—>data break; case 21: if(B->top—〉data break; case 23: if(B—〉top->data break; case 31: if(C—〉top-〉data〈A->top->data)A—〉push(C—>pop()); else cout〈<”ERROR!”; break; case 32: } if(C—〉top—〉data Outlin(); }while(C—>Top!=Store); 18 }; } cout〈〈”你太强了!!\\n”< int cord1,cord2; do { system(”cls”); cout<〈\"\\n\\n\\n\\\ 汉诺塔问题的动态演示 \\n\"; cout〈<”\\\ ——---—---———-——-——-08调查分析 周丽存(20080403143) \\n”; cout<〈\"\\n\\\ 1.建立汉诺塔\\n\"; cout<<\"\\n\\\ 2。算法思想\\n\"; cout<〈\"\\n\\\ 3.结束程序\\n”; cout<〈”\\\ -—---—-——--————-—-— \\n\"; cout〈〈”\\\ 请输入你的选择 (1,2,3):\"; cin>〉cord1; while(cord1>3||cord1〈1) { } cout<〈”-_-!”; cin>〉cord1; switch(cord1) { case 1: int ans; 19 cout〈〈”\\n\\\ 请输入层数(1—10):\"; cin〉〉ans; if(ans〈1) ans=1; if(ans>10) ans=10; hanoi=new Hanoi(ans); hanoi—>Outlin(); cout<〈\"\\n\"〈〈endl; system(\"pause”); do { system(\"cls”); cout〈<”\\n\\n\\n\\\ 汉诺塔 \\n”; cout〈〈”\\n\\\ 1.开始演示\\n\"; cout<〈”\\n\\\ 2。输出步骤\\n\"; cout〈〈\"\\n\\\ 3.游戏模式\\n\"; cout〈〈”\\n\\\ 4。返回主菜单\\n\"; cout〈<\"\\n\\\ 5.终止程序\\n”; cout<<”\\\ -——----—-———-—-—--—\\n”; cout<<\"\\\ 请输入你的选择 (1,2,3,4,5):\"; cin〉>cord2; while(cord2>5||cord2〈1) { cout<<”—_-!\"; cin>>cord2; } switch(cord2) { case 1: system(”cls”); hanoi—>MoveShow(); 20 delete hanoi; hanoi=new Hanoi(ans); break; case 2: system(\"cls\"); hanoi->OutStep(); cout<<”\\n”〈 case 3: system(\"cls”); hanoi—>GameMove(); delete hanoi; hanoi=new Hanoi(ans); break; case 4: break; case 5: exit(0); } }while(cord2〈=5&&cord2!=4); delete hanoi; break; case 2: system(”cls\"); Arithmetic(); break; case 3: exit(0); } 21 }while(cord1〈=3); return; } void Arithmetic() { string ans; cout<〈\"\\n\\n”; cout<〈” 把N层塔看做两部份:N—1,1(如图所示) ==== | | \" 〈 〈 〈 〈endl; cout 〈 <\" \"< cout〈〈\" A B C ”< cout〈〈\" [][][][][][] [][][][][][] [][][][][][] \"< cout<〈\" 3。把N—1部份移到C塔: \"〈 23 因篇幅问题不能全部显示,请点此查看更多更全内容