汉诺塔模拟程序报告.docx
- 文档编号:10921977
- 上传时间:2023-02-23
- 格式:DOCX
- 页数:25
- 大小:135.58KB
汉诺塔模拟程序报告.docx
《汉诺塔模拟程序报告.docx》由会员分享,可在线阅读,更多相关《汉诺塔模拟程序报告.docx(25页珍藏版)》请在冰豆网上搜索。
汉诺塔模拟程序报告
合肥学院
计算机科学与技术系
课程设计报告
2010~2011学年第一学期
课程
JAVA语言课程设计
课程设计名称
汉诺塔模拟程序
学生姓名
程伟
学号
0704031021
专业班级
网络工程
(1)班
指导教师
许强、张贯虹
2010年9月
一、需求分析
本次的课程设计的主要任务是:
设计一个模拟程序,图形化地展现汉诺塔的求解过程。
主要解决的问题是:
1.学习数据结构课程中关于汉诺塔的知识和算法。
N阶Hanoi塔,有3个柱子a、b、c,a柱子上从上至下叠放有n个直径由小到大、编号依次为1,2,…,n的圆盘。
现要求将a柱上的n个圆盘移至c柱,并仍按同样顺序叠放。
圆盘移动时须遵循以下原则:
1)每次只能移动一个圆盘。
2)圆盘可以插在a、b、c中的任何一个柱子上。
3)任何时刻都不能将一个较大的圆盘压在较小的圆盘之上。
圆盘的移动过程是一个递归调用过程。
2.设计图形界面,画出3个柱子和若干个大小不一的圆盘,圆盘数量可人工设定。
Frame是一种具有边框的容器,它是Java中最常用的容器之一,它又是JavaApplication程序的图形用户界面。
Frame只能作为最外层容器,不能被任何其他容器所包含。
下拉列表是一种“多选一”的输入界面,通常只可看见下拉列表的一个选项和它右边的箭头按钮。
当要改变盘子的个数时(即单击下拉列表中选中项),系统自动产生一个ItemEvent类对象所包含这个时间的信息,并将该对象作为实参传递给被自动调用的监听者的选择事件的响应方法。
3.当点击“开始”按钮后,系统自动展现圆盘的移动过程,一秒移动一次。
线程是进程中一段连续的控制流程或是一段执行路径。
在Java语言中,线程的创建有两种方式:
(1)定义一个Thread类的子类,并在该子类中重写run()方法,该run()方法是线程执行的起点;
(2)定义一个实现Runnable接口的类,并在该类中定义Runnable接口的run()方法,同样,该run()方法代表了线程执行的起点。
本程序中用到第二种创建线程的方法。
二、设计
2.1设计思想
本程序要求实现用图形界面,画出3个柱子和若干个大小不一的圆盘,同时圆盘数目可以人工设定,当点击“开始”按钮后,系统自动展现圆盘的移动过程,从而实现汉诺塔问题,其中圆盘移动速度是每秒移动一次。
1、所谓汉诺塔,既是一种游戏,游戏的装置是一块铜板,上面有3根杆,最左杆自下而上、由大到小顺序串有64个金盘,呈一个塔形(如图1.1所示)。
游戏要求把左边杆上的金盘全部移动到最右边的杆上,条件是一次只能够动一个盘子,并且不允许大盘放在小盘上面。
容易推出,n个盘从一根杆移到另一根杆需要2n-1次。
b
c
a
图1.1汉诺塔
汉诺塔算法属于递归算法,该算法过程为:
假定要把n个盘子按题目规定由a杆借助b杆移动到c杆。
模拟这一过程的算法称为autoMoveDisk(n,a,b,c)。
则有:
第一步:
先把上面的n-1个盘子设法借助b杆放到c杆,如图1.1中的箭头1)所示,记做autoMoveDisk(n,a,c,b);
第二步:
把第n个盘子从a杆直接移到b杆,如图1.1中箭头2)所示;
第三步:
把c杆上的n-1个盘子借助a杆移到b杆,如图1.1中的箭头3)所示,记做autoMoveDisk(n,c,a,b);
2、本程序定义了四个类,分别为:
1)Disk类,此类是继承了Button类,是他的一个子类,用于实现画出图形界面中的盘子,包括定义盘子数量,设置盘子的颜色,判断柱子最上面是否有盘子(设置和返回盘子的状态)。
该类在TowerPoint类和HannioTower类中都有被调用。
2)TowerPoint类,本类用于实现定义盘子的放置位置,即一个坐标点(盘子的中心点在塔上的位置),同时还能够判断柱子上某点上是否有盘子(设置和返回该点上盘子的状态),还能够完成在该点上放置盘子,将盘子加到容器里。
该类的初始化和真正实现是在HannioTower类中。
3)HannioTower类,此类中主要包括两个部分:
第一个部分:
设置塔上点的属性,根据盘子数来存储三根柱子上点的坐标(即盘子的放置位置)并设置该点上没有盘子。
同时设置盘子的属性,包括设置盘子的宽度和高度以及将盘子放到柱子上,并设置柱子最上面有盘子。
在图形界面上画柱子(即三根直线和一根水平直线),灰色矩形长条作为底座,用红色点标注盘子的放置位置和用A、B和C来标明三根柱子。
第二个部分:
也是核心部分,即汉诺塔算法通过函数的实现。
该算法在上面已有介绍,但在算法的第二步中(把第n个盘子从a杆直接移到b杆),要考虑到取a杆上的第n个盘子时,要判断是否有该盘子和获得该盘子,并获得该盘子的位置(为设置拿走后该位置上没有盘子的属性),以及在塔中获得盘子的放置位置。
最后将盘子的整个移动过程追加于文本域中。
4)Tower类,该类为主类。
主类使用Frame容器作为JavaApplication程序图形用户界面的。
用于实现整个图形界面的布局(界面布局为边界布局),两个按钮、下拉按钮和文本域的定义及事件的监听。
若点击“自动演示”按钮,判断线程是否存活,若不存活则创建线程;若点击“重新开始”按钮,若线程不存活,则重新构建图形界面,恢复到原始状态;若重新选择盘子数,则也重新构建图形界面,恢复到新的原始状态。
线程的实现是通过该类实现了Runnable接口,并在该类中定义Runnable接口的run()方法,该方法代表了线程的执行起点。
2.2详细设计
2.2.1程序流程图(汉诺塔程序流程图)
2.2.2程序代码说明
程序中引入的包:
packagecode;
importjavax.swing.*;
importjava.awt.*;
importjava.awt.event.*;
(1)盘子类:
类名:
Disk
作用:
定义图形界面中的盘子属性
继承的父类名:
Button
publicclassDiskextendsButton{}
定义的对象:
intnumber//盘子的个数
booleanisTop=false//判断柱子最上面是否有盘子
主要成员方法:
publicbooleangetIsTop()//返回最上面是否有盘子的属性
publicvoidsetIsTop(booleanb)//设置最上面是否有盘子的属性
publicintgetNumber()//返回盘子个数
(2)盘子的放置位置类
类名:
TowerPoint
作用:
定义塔上点的坐标,即盘子的放置位置
publicclassTowerPoint{}
定义的对象:
intx,y//塔上的点位置,即盘子的放置位置
booleanisHaveDisk//判断点上是否有盘子
Diskdisk//定义盘子类的对象
HannoiTowercon//定义一个HannoiTower类的对象
主要成员方法:
publicbooleangetIsHaveDisk()//返回点上是否有盘子的属性
publicvoidsetIsHaveDisk(booleanboo)//设置点上是否有盘子的属性
publicintgetX()//获得点位置坐标x
publicintgetY()//获得点位置坐标y
publicvoidputDisk(Diskdisk,HannoiTowercon)//在点上放盘子
publicDiskgetDisk()//返回Disk类型
(3)汉诺塔模拟程序类
类名:
HannoiTower
作用:
设置踏上点属性、设置盘子属性、汉诺塔模拟程序
继承的父类名:
JPanel
publicclassHannoiTowerextendsJPanel{}
定义的对象:
TowerPointpoint[]//塔上点数组
booleanmove=false//判断是否移动
Diskdisks[]//盘子数组
intdiskNum=0//定义盘子个数
intwidth,height//盘子的宽度和高度
chartowerName[]={'A','B','C'}//塔名
TextAreainfoArea//定义一个文本域
intautoNum=1//计算步数
主要成员方法:
publicvoidpaint(Graphicsg)//画主界面中的柱子
publicvoidautoMoveDisk(intdiskNum,charone,chartwo,charthree)//自动演示函数
publicDiskgetTopDisk(chartowerN)//取最上面的盘子
publicintgetTopDiskUp(chartowerN)//在塔中获取盘子的放置位置
publicintgetTopDiskPosition(chartowerN)//获得最上面盘子的位置
publicvoidpause()//盘子移动速度是每秒移动一次
(4)主类
类名:
Tower
作用:
设置界面布局,和进行事件监听
继承的接口名:
ActionListener,ItemListener,Runnable
继承的父类名:
Frame
publicclassTowerextendsFrameimplementsActionListener,ItemListener,Runnable{}
定义的对象:
HannoiTowertower//定义一个HannoiTower类的对象
JButtonrenew,auto//定义两个按钮
ChoicediskNumComBox//定义一个下拉按钮
chartowerName[]={'A','B','C'}//定义塔名
intdiskNum,diskWidth,diskHeight//存储盘子数目、宽度和高度
Threadthread//定义一个线程
TextAreainfoArea//定义一个文本域
主要的成员方法:
publicvoidactionPerformed(ActionEvente)//事件的响应程序
publicvoiditemStateChanged(ItemEvente)//事件的响应程序
publicvoidrun()//线程的启动
publicstaticvoidmain(Stringargs[])//主函数
三、调试及测试
(1)调试过程中遇到的主要问题及解决方法
1如何利用线程控制盘子的移动?
Java语言是第一个语言本身就支持线程的主流编程语言,其对线程的支持主要通过java.lang.Thread类和java.lang.Runnable接口来实现。
本类实现了Runnable接口,并在该类中定义Runnable接口的run()方法。
当点击“自动演示”时,创建线程,从新布局界面。
在此函数中用到了remove()函数,它是Frame中的函数,从此窗体中移除指定的菜单栏。
2如何获得盘子的宽度和长度?
以及如何将盘子放到指定的位置?
经过上网查询,获得盘子的宽度和长度需要getBounds()此函数,它以Rectangle对象的形式获取组件的边界。
如果不知道如何将盘子放到指定的指定的位置,则得到如图3.1的结果:
图3.1
为了使盘子放在指定的位置,需要setBounds()此函数,它能移动组件并调整其大小,他有四个参数,前两个参数表示控件的位置坐标,后面两个参数表示控件的宽度和高度。
3在汉诺塔算法的第二步中,如何把第n个盘子从a杆移到b杆?
要考虑到取a杆上的第n个盘子时,要判断是否有该盘子和获得该盘子,并获得该盘子的位置(为设置拿走后该位置上没有盘子的属性),以及在塔中获得盘子的放置位置。
4在paint()函数中super.paint(g),它同repaint()的功能是一样的,都是重新画界面。
5当执行汉诺塔算法时,如果将盘子从一个塔上移动到另一个塔上时,该盘子应该从第一个塔上移除,否则会出现下面的情况:
图3.2
盘子移动后,仍然在之前的柱子上,因此需要用到Frame中的remove()函数用来移除。
正确结果如图3.3:
图3.3
(2)程序运行的时空效率分析
该应用程序并没使用多少数据结构的知识,主要是在求解汉诺塔问题时,涉及到递归调用的算法。
所谓递归,就是一个直接调用自己或通过一系列的调用语句间接地调用自己的过程。
随着盘子的增多,它占用的时间也会越来越多,n个盘子从一根杆移到另一根杆需要2n-1次。
同时还有点的存储和盘子的存储都用到了数组。
其他的部分只是使用了面向对象中的方法和对象,都是一些基本的语句,并没有用到多少数学算法。
(3)测试数据集
分别编译这4个Java源文件,或运行“javac*.java”命令,编译全部的源文件,然后运行主文件,即Tower类。
初始化界面,结果如图3.4:
图3.4
点击下拉按钮,选中3个盘子,结果如图3.5:
图3.5
结果分析:
当在下拉按钮中选中3时,事件监听者会调用事件响应程序,即publicvoiditemStateChanged(ItemEvente),重新构建界面,盘子数设置为3,同时将文本域设置为空,重新画盘子数
点击“自动演示”后,结果如图3.6:
图3.6
结果分析:
点击“自动演示”按钮后,会根据汉诺塔算法自动将盘子从A塔转移到C塔上,同时将移动过程追加到文本域中。
点击“重新开始”,结果如图3.7:
图3.7
结果分析:
点击“重新开始”按钮后,他会判断如果不存活的话,就会从此窗体移除指定的菜单栏,然后从新设置文本域和从画HannoiToewer类中的界面。
点击下拉按钮,选中5个盘子,结果如图3.8:
图3.8
四、经验和体会
此次课程设计的题目为汉诺塔模拟程序,通过课程设计,进一步巩固、加深我们所学专业课程《JAVA语言教程》的基本理论知识,理论联系实际,进一步培养我们的综合分析问题,解决问题的能力;全面考核我们所掌握的基本理论知识及其实际业务能力,从而达到提高学生素质的最终目的;利用所学知识,开发小型应用系统,掌握运用JAVA语言编写调试应用系统程序,训练独立开发应用系统,进行数据处理的综合能力;对于给定的设计题目,如何进行分析,理清思路,并给出相应的数学模型;熟练掌握JAVA语言的GUI设计、线程技术,灵活运用各种类库,为今后从事实际工作打下坚实的基础。
通过该课程设计,全面系统的理解了JAVA语言的一般原理和基本实现方法。
把死板的课本知识变得生动有趣,激发了学习的积极性。
把学过的JAVA的知识强化,能够把课堂上学的知识通过自己设计的程序表示出来,加深了对理论知识的理解。
我经常和同组成员很好的讨论了此程序的相关问题,并上网查询了很多不懂得问题,终于完成了汉诺塔模拟程序。
程序基本实现了该课程设计的基本要求。
在设计的过程中了解到自己的知识还是比较有限,更肯定了自己再以后学习编程的道路上的坚定不移,同时也让我懂得组合作的重要性。
但由于只学习了一个学期的Java语言,自己水平有限,使得程序还是有些不完善的地方。
回顾起此次Java课程设计,至今我仍感慨颇多,的确,从拿到题目的开始,从理论到实践,在整整两个星期的日子里,可以说是苦多于甜,但是可以学到很多很多的东西,同时不仅可以巩固了以前所学的知识,而且学到了很多在书本上所没有学到过的知识。
通过这次课程设计使我懂得了理论与实践相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正掌握这门技术,也提高了自己的独立思考的能力。
在设计的过程遇到问题,可以说得上是困难重重,这毕竟第一次做的,难免会遇到各种各样的问题,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固,通过这次课程设计之后,一定把以前所学的知识重新温故。
通过此次课程设计,将我我本学期所学的Java知识得到巩固和应用,在设计的过程中,我遇到了很多问题,不过在朋友和同学的帮助和自己的思考下还是很好的完成了。
这次课程设计还让我懂得了写程序不能闭门造车,要努力拓宽知识面,开拓视野,拓宽思维。
它还让我学会了在网上查阅那些无限的资料。
让我不仅学会了书本上的知识,还让自己能够面对困难并且克服它。
更重要的的是如何通过组的合作,来完成一份作业,它更需要彼此的耐心,容忍力,遇到难题不会迁怒别人,而是很好的与他人沟通,认真的来完成。
附录:
主要源程序
(1)Disk.java
packagecode;
importjava.awt.*;
publicclassDiskextendsButton{
intnumber;//盘子的个数
publicDisk(intnumber){this.number=number;
setBackground(Color.yellow);}
publicintgetNumber(){returnnumber;}}
(2)TowerPoint.java
packagecode;
importjava.awt.*;
publicclassTowerPoint{
intx,y;//塔上的点位置,即盘子的放置位置
booleanisHaveDisk;//判断点上是否有盘子
Diskdisk;HannoiTowercon;
publicTowerPoint(intx,inty,booleanboo){this.x=x;this.y=y;isHaveDisk=boo;}
publicbooleangetIsHaveDisk(){returnisHaveDisk;}
publicvoidsetIsHaveDisk(booleanboo){isHaveDisk=boo;}
publicintgetX(){returnx;}//获得点位置坐标
publicintgetY(){returny;}
publicvoidputDisk(Diskdisk,HannoiTowercon){//在点上放盘子
this.con=con;con.setLayout(null);//设置布局
this.disk=disk;con.add(disk);//加盘子到容器中
intw=disk.getBounds().width;//获得盘子的长和宽getBounds()以Rectangle对象的形式获取组件的边界
inth=disk.getBounds().height;
disk.setBounds(x-w/2,y-h/2,w,h);//setBounds()移动组件并调整其大小,控件位置坐标,后面是宽度和高度
isHaveDisk=true;con.validate();}
publicDiskgetDisk(){returndisk;}}
(3)HannoiTower.java
packagecode;
importjavax.swing.*;
importjava.awt.*;
publicclassHannoiTowerextendsJPanel{
TowerPointpoint[];//塔上点数组
booleanmove=false;//判断是否移动
Diskdisks[];//盘子数组
intdiskNum=0;//定义盘子个数
intwidth,height;//盘子的宽度和高度
chartowerName[]={'A','B','C'};//塔名
TextAreainfoArea;
intautoNum=1;//计算步数
publicHannoiTower(intnumber,intw,inth,char[]name,TextAreatext){towerName=name;diskNum=number;width=w;height=h;
infoArea=text;setLayout(null);
disks=newDisk[diskNum];//初始化盘子个数
//设置塔上的点属性
point=newTowerPoint[3*diskNum];//塔上点的个数=3*盘子个数
intspace=20;
for(inti=0;i point[i]=newTowerPoint(40+width,100+space,false);//设置点的位置和没有盘子 space=space+height;} space=20; for(inti=diskNum;i<2*diskNum;i++){//第二根柱子上的点 point[i]=newTowerPoint(200+width,100+space,false); space=space+height;} space=20; for(inti=2*diskNum;i<3*diskNum;i++){//第三根柱子上的点 point[i]=newTowerPoint(360+width,100+space,false); space=space+height;} //设置盘子属性 inttempWidth=width; intsub=(int)(tempWidth/diskNum); for(inti=diskNum-1;i>=0;i--){disks[i]=newDisk(i); disks[i].setSize(tempWidth,height);//设置盘子的宽和高 tempWidth=tempWidth-sub;} for(inti=0;i }} publicvoidpaint(Graphicsg){super.paint(g); g.drawLine(point[0].getX(),point[0].getY(),point[diskNum-1].getX(),point[diskNum-1].getY());//画3根竖线 g.drawLine(point[diskNum].getX(),point[diskNum].getY(), point[2*diskNum-1].getX(),point[2*diskNum-1].getY()); g.drawLine(point[2*diskNum].getX(),point[2*diskNum].getY(), point[3*diskNum-1].getX(),point[3*dis
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 汉诺塔 模拟 程序 报告
![提示](https://static.bdocx.com/images/bang_tan.gif)