数据结构课程设计马踏棋盘求全部解及演示程序讲解.docx
《数据结构课程设计马踏棋盘求全部解及演示程序讲解.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计马踏棋盘求全部解及演示程序讲解.docx(29页珍藏版)》请在冰豆网上搜索。
数据结构课程设计马踏棋盘求全部解及演示程序讲解
安徽工程大学信息10课程设计
马踏棋盘的求解及演示设计
摘要
数据结构是计算机科学与技术专业的一门核心专业基础课程,是一门理论性强、思维抽象、难度较大的课程。
我认为学习数据结构的最终目的是为了获得求解问题的能力。
对于现实世界中的问题,我们应该能从中抽象出一个适当的数学模型,该数学模型在计算机内部用相应的数据结构来表示,然后设计一个解此数学模型的算法,再进行编程调试,最后获得问题的解答。
《数据结构》课程设计是计算机科学技术专业集中实践性环节之一,是学习完《数据结构》课程后进行的一次全面的综合练习。
开设本课程设计实践的主要目的就是要达到理论与实际应用相结合,提高学生的动手能力,完成计算机应用能力的培养;本课程设计主要解决马踏棋盘的问题,找出踏遍棋盘的多种路径,并实现动态要是过程。
马踏棋盘问题,实际上是图论中的哈密顿通路问题,是典型的NP问题,求解的问题与算法设计有很大关系,如果采取穷举搜索的话,很容易陷入海量搜索的状态,耗费巨大的时间,使问题几乎不可解,因此马在棋盘上遍历采用算法当中的深度优先算法和启发式贪心算法,用栈来存储遍历过程,通过对栈的使用实现对所有路径的搜索。
在调试过程发现,启发式贪心算法,针对于马踏棋盘问题有着极大的好处,就是无论从棋盘上哪个点开始,找到一条遍历完棋盘的通路是不需要回溯的,也就节省了大量的时间,而试探性的操作对于每个点都也只有168步,所以求出所有路径在不到一秒的时间内完成。
关键词:
马踏棋盘;骑士周游;哈密顿通路;NP-完全问题;贪心算法;回溯法;
第一章引言
本课程设计主要研究马踏棋盘的问题,即骑士周游问题,是将马随机放在国际象棋的8×8棋盘的某个方格中,“马”按照走棋规则进行移动,要求每个方格只进入一次,走遍棋盘上全部64个方格。
许多知名的数学家,如德莫弗(DeMoivre)、欧拉(Euler)与范德蒙德(Vandermonde)等人,在过去的200年中都研究过这个问题,今天从数据结构的角度,解决这一问题。
力求以最快的速度,即最高的效率来解决问题。
已知穷举法是几乎不可能完成的,而与解决迷宫问题的回溯法,也要占用大量的时间,这里采用贪心算法来解决这一问题,并找出多有的遍历路径。
第二章需求分析
2.1问题描述
马随机放在国际象棋的8×8棋盘的某个方格中,“马”按照走棋规则进行移动,要求每个方格只进入一次,走遍棋盘上全部64个方格。
设计一个国际象棋的马踏遍棋盘的演示程序。
2.2基本要求
设计合适的数据结构,编制递归以及非递归程序,求出马的行走路线,并按求出的马的行走路线,将路线1,2,…,64依次填入一个8×8的方阵,输出之,若有多种走法,则能将全部的输出。
必须要能够将踏遍棋盘的过程显示在计算机屏幕上。
要求:
(1)描述设计所涉及的数据模型,设计高效的数据结构完成总体设计,搭好框架,确定人机对话的界面(要求界面上能动态体现出演示的过程),实现功能;
(2)界面友好,函数功能要划分好
(3)要有算法设计的流程图
(4)程序要加必要的注释
(5)要提供程序测试方案
2.3具体需求
1、首先要找到马踏棋盘棋盘的多条路径。
2、实现马踏棋盘的动态演示过程。
3、优化算法,提高算法效率,以递归与非递归的方式实现
2.4开发环境
开发环境:
Windows8
辅助工具:
VisualStudio2012,MyEclipse10.5
运行环境:
WindowsXP/Vista/7/8
第三章概要设计
3.1系统概述
3.11系统流程图
3.12主函数main()的执行流程
求解多条路径子系统:
自动演示路径子系统
N
Y
N
Y
3.2系统描述
通过VS2012完成的寻找多条路径的子系统,通过java来实现马踏棋盘的动态演示子系统。
在寻找多条路径的子系统中,通过启发式贪心算法,将某点的下一步最少通往其它落脚点,将该点确定为最佳落点。
每次只走下一步通向其他点最少的点。
用栈记录探寻的过程,将走过的点标记为1,试探而没有走的点标记为0.最后通过寻找出栈标志为0的点来寻找其他路径。
在动态显示模块式通过java的线程机制是先的自动动画演示。
3.3逻辑设计
抽象数据类型
棋盘上某点的位置坐标结构体Postion
把个方向试探的增量位置数组direct[8]
棋盘某点通向其他点的可到达数的二位数组access[8][8]
链栈
用来记录可到达下一位置坐标的数组:
nextPath[8];
用来记录整个遍历过程的数组:
tourpos[64];
第四章详细设计
4.1功能模块设计
4.1.2创建模块
本模块创建棋盘,以及棋盘上每一点的可到达数,一个向8个方向试探的增量数组。
以及记录整个遍历流程的链栈。
选择或设计数据结构的存储结构,实现存储结构的基本运算、设计的模块构成、各模块的简要说明、流程图、调用关系表等。
在这个过程中,要综合考虑系统功能,使得系统结构清晰、合理、简单和易于调试,抽象数据类型的实现尽可能做到数据封装,基本操作的规格说明尽可能明确具体。
详细设计的结果是对数据结构和基本操作作出进一步的求精,写出数据存储结构的类型定义,写出函数形式的算法框架。
4.1.3操作模块
实现对棋盘的周游,并找到多条路径
4.1.4显示模块
将找到的所有路径显示在屏幕上,并统计找到的路径数。
4.1.5自动演示模块
通过Java的Applet和线程机制,实现对找到的路径进行动态演示。
4.2数据结构设计
4.2.1数据设计
定义棋盘上某点的位置坐标结构体Postion
typedefstruct
{
intx;
inty;
}Postion;
定义把个方向试探的增量位置数组
Postiondirect[8]={{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1},{-1,2},{-2,1}};
定义棋盘某点通向其他点的可到达数的二位数组
intaccess[8][8]={
{2,3,4,4,4,4,3,2},
{3,4,6,6,6,6,4,3},
{4,6,8,8,8,8,6,4},
{4,6,8,8,8,8,6,4},
{4,6,8,8,8,8,6,4},
{4,6,8,8,8,8,6,4},
{3,4,6,6,6,6,4,3},
{2,3,4,4,4,4,3,2}
};
定义一个以某一棋盘上的点和标志的类型,作为栈的存储数据
typedefstruct{
Postionp;
intflag;
}DataType;
定义一个链栈:
typedefstructnode//定义结点结构
{
DataTypedata;
structnode*next;
}StackNode,*PStackNode;
////////////////////////////////////////
typedefstruct//定义一个栈
{
PStackNodetop;
}LinkStack,*PLinkStack;
用来记录可到达下一位置坐标的数组:
PostionnextPath[8];
用来记录整个遍历过程的数组:
Postiontourpos[64];
4.3算法设计
开始
寻找下一条路径:
流程图:
略:
算法描述:
应考察每一方格的可到达性。
使用数组accessibility[]表示可达到数,并当马踏棋盘时,程序动态修正剩余格子的可达到数。
accessibility[arrayPos]=0表明格子已经被占据。
算法:
voidnext_Path(PostionP)
{
PostiontestPos;
for(inti=0;i<8;i++)
{//有八种到达的情况
testPos.x=P.x+direct[i].x;//得出X,Y坐标的测试位置
testPos.y=P.y+direct[i].y;
if(checkPath(testPos))
{//判断测试位置是否在棋盘内
nextPath[arrayPos]=testPos;//由测试位置给出正确X,Y坐标
accessibility[arrayPos]=access[testPos.x][testPos.y];//利用对应的X,Y坐标得出相应的可到达的路径总数
if(accessibility[arrayPos]>0)//accessibility[arrayPos]=0表明格子已经被占据
arrayPos++;
}//寻找空格子结束
}//结束for循环,寻找结束
countAccessibility=arrayPos;//统计可达到数
if(countAccessibility>0)
{
sortAll();
}
arrayPos=-1;
}
////////////////////////////////////////////////////////////////
2.使用冒泡法来查询最小数。
voidsortAll()
{//冒泡排序法.冒泡排序的基本概念是:
依次比较相邻的两个数,将大数放在前面,小数放在后面。
//保持稳定性
inttemp;
Postiontemps;
for(inti=0;i{
for(intj=i+1;j{
if(accessibility[i]>accessibility[j])
{
temps=nextPath[i];
nextPath[i]=nextPath[j];
nextPath[j]=temps;
temp=accessibility[i];
accessibility[i]=accessibility[j];
accessibility[j]=temp;
}//endofif
}//endofinnerfor
}//endofouterfor
}//endofsortAll
3.//////////////////////////////////////////////
3、向下一步移动,将当前要走的结点入栈,标记为1,其他可到达但没有走的点入栈,标记为0
如果当前坐标走过,那么它可以到达的其它点的可到达数应该-1
最后将该点的可到达数更新为0
voiddomoving(PostionP)
{
for(inti=0;i{
DataTypeq;
q.p=nextPath[i];
if(i==0)
{
q.flag=1;
}else
{
q.flag=0;
}
Push_LinkStack(S,q);
access[nextPath[i].x][nextPath[i].y]--;
}
//直到没有路径了
access[P.x][P.y]=0;//当前位置置0
}
4、打印路径:
打印8×8棋盘,在棋盘中显示马跳的步骤:
voidfprint()
{//输出路径
intorder[8][8]={0};//-----初始化
for(intk=0;k<64;k++)
{
order[tourpos[k].x][tourpos[k].y]=k;
}
cout<<"\n棋盘表示\n";
cout<<"01234567\n";
cout<<"+----+----+----+----+----+----+----+----+\n";
for(inti=0;i<8;i++)
{
printf("");
printf("%2d",i);
for(intj=0;j<8;j++)
{
printf("|%2d",order[i][j]);
}
printf("|");
printf("\n");
if(i==7)
printf("+----+----+----+----+----+----+----+----+");
else
printf("+----+----+----+----+----+----+----+----+");
printf("\n");
}
printf("");
}
5、寻找其他路径:
算法描述:
将栈中存储的路径出栈,判断标记是否为0,并累计标记为1的个数count_next,即走过的步数,方便撤销走过的步骤,根据count_next来撤销走过的步骤,先将在access[][]撤销,即还原为1,将当前为flag为0的复制到下一步的tourpos[]数组中,之后将tourpos[]后面的步骤还原为0,再结束后,在寻找下一条路径,若找不到,则继续出栈,向前回溯。
voidother_Path()
{//寻找其他路径
intcount=0;
intrecount=0,coutpath=0,count_next=0;
DataTypePs[169];
while(!
Empty_LinkStack(S))
{intflag=0;
Pop_LinkStack(S,&Ps[count]);
if(Ps[count].flag!
=0)
{
count_next++;
}
if(Ps[count].flag==0)
{
access[tourpos[63-count_next].x][tourpos[63-count_next].y]=1;
tourpos[63-count_next]=Ps[count].p;
for(inti=0;i{
access[tourpos[63-i].x][tourpos[63-i].y]=1;
tourpos[63-i].x=0;
tourpos[63-i].y=0;
}
access[tourpos[63-count_next].x][tourpos[63-count_next].y]=0;
for(intj=count_next;j>0;j--)
{
if(!
tour_next(tourpos[63-j],63-j))
{
flag=1;
break;
}
}
if(flag!
=1){
coutpath++;
fprint();
}
}
count++;
}
cout<cout<<"周游结束共找到"<}
动态演示:
根据JAVA线程机制,每隔800毫秒动画演示1步。
publicvoidrun(){
//启动线程后将自动调用run()方法,在run()方法内产生一个控制动画的循环
intdelay=800;
while(true){
count=0;
for(inti=0;i<64;i++){
repaint();//repaint()将调用paint()方法画一帧图像
count++;
if(recount>63)
{
finalFramefrom=newFrame();
JOptionPane.showMessageDialog(from,"周游完成");
return;
}
try{
Thread.sleep(delay);
}catch(Exceptione)
{}
}
}
}
第五章调试与分析
5.1调试分析
经过对程序的编制,调试和运行,使我更好的掌握了栈基本性质和有关马的遍历问题的解决方法,熟悉了各种调用的数据类型,在调试和运行过程中使我更加的了解和熟悉程序运行的环境,提高了我对程序调试分析的能力和对错误的纠正能力。
5.1.1、
首先要检测贪心算法的可用性,先找出一条路径;检测输出的路径是否合法
5.1.2、
完成一条路径的输出之后,进行栈的检查,检查栈中存储的元素是否正确能否满足回溯的标准,经过检测栈的合法性才能对栈中元素进行操作,最后就是,实现对其他路径的寻找,并统计路径的条数。
第六章系统试用说明
6.1系统试用说明
系统提示用户输入测试坐标,输入坐标应满足必须为整数,且大于等于0,小于8两点之间以空格隔开。
及满足在棋盘上点的的要求。
测试数据:
00;10;77,23
第七章总结与体会
通过本次课程设计掌握了关于数据结构的很多内容如算法的设计,栈的使用,对图的深度优先遍历算法有了更深入的了解,对于马踏棋盘这一问题,有了独到研究和见解,让学习的理论与实际应用相结合,提高了我的动手能力,以及独立解决问题的能力,如使用Java来动态演示马踏棋盘的步骤,本来学习java是对于用于动画的线程机制就没有深入了解,经过这次的课程设计,在网上查阅资料,在几天内,我学会了如何使用java的线程机制来实现动画演示程序,可对以说是一个不小的受获。
对数据结构的应用上也得到很大的提升,前面做实验都是一些验证性的实验,只是把书上的代码输进去,检测它的正确性,和它的算法思想,而这次是在问题的前提下,来确定数据结构,在算法思想的前提下,来确定算法的使用,并根据各种可行的算法来确定最优的算法,即时空效率最高。
并且在写出解决查找多种路径的算法后,很有成就感,因为在网上,这一问题只有求出一条路径的方法,也没有动态演示的,很不符合课程设计的要求,并且发现,如果只找一条路径的话,要是算法用的灵活,可以说没学数据结构之前也可解决,所以在找到所有路径的时候内心很喜悦,大概这就是编程的乐趣吧。
本次数据结构课程设计确实收益匪浅。
参考文献
×××××××××××××××××××××××××××××××××××××××××××
参考文献书写格式应符合GB7714-87《文后参考文献著录规则》。
常用参考文献编写项目和顺序规定如下:
先安排中文(按姓氏笔划排序),后安排英语(或其他语种)(按字母先后排列);
注释置于页脚,参考文献置于文末。
参考文献只列出最主要的、且是公开发表的文献,非正式公开发表的资料不列。
文献主要类型格式如下:
期刊:
[序号]作者.篇名[J].
附录//NP_compelte.cpp:
定义控制台应用程序的入口点。
//
//NP_compelte.cpp:
定义控制台应用程序的入口点。
//
#include"stdafx.h"
#include
usingnamespacestd;
#defineMax100
typedefstruct
{
intdx;
intdy;
}direct_increment;
direct_incrementdirect_ay[8]={{1,2},{2,1},{2,-1},{-1,-2},{-2,-1},{1,-2},{-1,2},{-2,1}};
intaccess[8][8]={
{2,3,4,4,4,4,3,2},
{3,4,6,6,6,6,4,3},
{4,6,8,8,8,8,6,4},
{4,6,8,8,8,8,6,4},
{4,6,8,8,8,8,6,4},
{4,6,8,8,8,8,6,4},
{3,4,6,6,6,6,4,3},
{2,3,4,4,4,4,3,2}
};
intaccessibility[8];
intcountAccessibility;
typedefstruct
{
intx;
inty;
}Postion;
staticPostionnextPath[8];
staticPostiontourpos[64];
staticintarrayPos=0;
staticintownAccessibility;//当前棋子的可到达数
staticintcountMoving=-1;
boolsuccess=false;
//////////////////////////////////////
typedefstruct{
Postionp;
intflag;
}DataType;
typedefstructnode//定义结点结构
{
DataTypedata;
structnode*next;
}StackNode,*PStackNode;
////////////////////////////////////////
typedefstruct//定义一个栈
{
PStackNodetop;
}LinkStack,*PLinkStack;
/////////////////////////////////////////
////////////////////////////////////////
PLinkStackInit_LinkStack()//初始化函数
{
PLinkStackS;
S=(PLinkStack)new(LinkStack);
if(S)
S->top->next=NULL;
return(S);
}
/////////////////////////////////////////////////////
boolEmpty_LinkStack(PLinkStackS)//判断栈空函数
{
return(S->top==NULL);
}
//////////////////////////////////////////////////////
intPush_LinkStack(PLinkStackS,DataTypex)//入栈函数
{
PStackNodep;
p=new(StackNode);
if(!
p)
{