数据结构课程设计206.docx
- 文档编号:8497052
- 上传时间:2023-01-31
- 格式:DOCX
- 页数:17
- 大小:158.85KB
数据结构课程设计206.docx
《数据结构课程设计206.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计206.docx(17页珍藏版)》请在冰豆网上搜索。
数据结构课程设计206
数据结构课程设计报告
姓名:
赵维月
班级:
软092
老师:
王森玉
学号:
099074206
实验一.马的遍历
目录
1.流程图:
1
2.问题描述:
2
3.设计思路:
2
4.数据结构设计:
2
5.功能函数算法分析:
3
(1)计算一个点周围有几个点函数intCount(intx,inty)3
(2)寻找下一个方向函数intFind_Direction(intx,inty)3
(3)栈的相关函数:
4
(4)骑士遍历函数:
voidKnight(intx,inty,intv)5
(5)主函数:
voidmain()6
(6)棋盘初始化函数voidMark_Che(intv)7
(7)标记初始化函数voidMark_Dir(intv)8
6.运行和测试:
8
7.心得体会:
10
马的遍历问题
1.流程图:
假
真
假
真
2.问题描述:
在中国象棋棋盘上,对任意位置上放置的一个马,均能选择一个合适的路线,使得该棋子(马)能按象棋的规则不重复的走过棋盘上的每一个位置。
要求依次输出所有走过的各位置的坐标。
3.设计思路:
首先,中国象棋是10*9的棋盘,马的走法是“马走日”,忽略“蹩脚马”的情况。
其次,这个题目采用的是算法当中的深度优先算法和回溯法:
在“走到”一个位置后要寻找下一个位置,如果发生“阻塞”的情况,就是后面走不通的情况,则向后回溯,重新寻找。
在寻找下一步的时候,对周围的这几个点进行比较,从而分出优劣程度,即看它们周围可以走的点谁最少,然后就走那条可走路线最少的那条。
经过这样的筛选后,就会为后面的路径寻找提供方便,从而减少回溯次数。
最后,本程序的棋盘和数组类似,因而采用数组进行存储,同时因为有回溯,所以采用栈的方法,并且为了最后打印方便,采用的是顺序栈的方法。
同时还有八个方向的数组,和为栈设计的每个点周围的八个方向那些可以走的数组。
4.数据结构设计:
同上面述,棋盘采用数组形式,并且这里的数组比棋盘的数组规模稍大,因为为了判断的方便,这里在棋盘周围各加了两层“墙”。
具体数据结构定义如下:
intchessboard[14][13];//采用最大的中国象棋10*9制的
intCanPass[14][13][8];//每个棋子的八个方向哪些可以走
typedefstruct
{//棋盘的八个方向
inty;
intx;
}direction;
directiondir[8]={{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1}};//八个方向
typedefstruct
{//栈的节点结构
intx,y;//走过位置
intdi;//走向下一个方向
}pathnode;
typedefstruct{
pathnodepa[90];//栈的容量最大为90
inttop;//栈顶
}path;//顺序栈
5.功能函数算法分析:
(1)计算一个点周围有几个点函数intCount(intx,inty)
该函数实现的功能是在遍历的过程当中计算一个点周围有几个方向可以走,从而为后面的筛选提供依据。
时间复杂度为
intCount(intx,inty)
{//计算每个节点周围有几个方向可以走
intcount=0,i=0;
for(i=0;i<8;i++)
if(chessboard[x+1+dir[i].x][y+1+dir[i].y]==0)
count++;
returncount;
}
(2)寻找下一个方向函数intFind_Direction(intx,inty)
该函数的功能是在走过一个点之后,寻找下一个适合的点,如果找到返回正常的方向值,否则返回-1。
时间复杂度为
intFind_Direction(intx,inty)
{//寻找下一个方向
intdire,min=9,count,d=9;
for(dire=0;dire<8;dire++)
{
if(chessboard[x+1+dir[dire].x][y+1+dir[dire].y]==0&&CanPass[x+1][y+1][dire]==0){
count=Count(x+dir[dire].x,y+dir[dire].y);
if(min>count){
min=count;
d=dire;
}
}
}
if(d<9)
returnd;
else
return-1;
}
(3)栈的相关函数:
初始化栈:
voidInit_Path(path*p);p是用到得栈;
判断栈是否是空:
intEmpty(pathp);p是栈,是空的话返回1,否则返回0,时间复杂度为;
压栈函数:
intPush_Path(path*p,pathnodet,intv)p是栈,t是压进去的节点,v是棋盘,时间复杂度为;
出栈函数:
intPop_Path(path*p,pathnode*t)p是栈,t是拿出来的节点,时间复杂度为。
voidInit_Path(path*p)
{//初始化栈
p->top=-1;
}
intPush_Path(path*p,pathnodet,intv)
{//压节点及其向下一位移动的方向入栈
if(p->top>=63+26*v)
return-1;
else
{
p->top++;
p->pa[p->top].x=t.x;
p->pa[p->top].y=t.y;
p->pa[p->top].di=t.di;
return1;
}
}
intEmpty(pathp)
{//判断栈是否为空
if(p.top<0)return1;
return0;
}
intPop_Path(path*p,pathnode*t)
{//出栈
if(Empty(*p))
return-1;
else
{
t->x=p->pa[p->top].x;
t->y=p->pa[p->top].y;
t->di=p->pa[p->top--].di;
return1;
}
}
(4)骑士遍历函数:
voidKnight(intx,inty,intv)
这是该算法的精华部分,x,y表示入口地点,v表示棋盘类型即中国象棋,这个函数主体是一个循环,循环里面始终是在找下一个点,如果找到就将该点进栈,找不到则退栈。
直到发生栈为空时退栈或循环结束,前一种情况时会提示找不到路径(虽然不会发生,但是为逻辑严密性依然要如此),后一种情况则打印出走过的正确路径和走过之后的数组,时间复杂度为。
voidKnight(intx,inty,intv)//x,y表示出发位置
{//骑士遍历函数
intnum=1,t,i;
pathp;
pathnodef;
Init_Path(&p);
for(num=1;num<=64+26*v;num++)
{
t=Find_Direction(x,y);
if(t!
=-1)
{//正常找到下一个方向的情况下
chessboard[x+1][y+1]=num;
f.x=x;f.y=y;f.di=t;
Push_Path(&p,f,v);
x=x+dir[t].x;y=y+dir[t].y;
}
elseif(num==64+26*v&&chessboard[x+1][y+1]==0)
{//最后一次时t肯定是-1
chessboard[x+1][y+1]=num;
f.x=x;f.y=y;f.di=t;
Push_Path(&p,f,v);
}
else
{
if(Pop_Path(&p,&f)==-1)
{//出栈且栈为空的情况
printf("!
!
!
!
!
!
!
!
!
!
!
!
无法为您找到一条适合的路径!
!
!
!
!
!
!
!
!
!
!
!
\n");
exit(0);
}
num-=2;
x=f.x;y=f.y;
CanPass[x+1][y+1][f.di]=1;
}//endelse
}
//根据栈中信息打印出骑士行走路径
printf("骑士巡游路径如下:
\n");
for(i=0;i<64+26*v;i++)
{
printf("(%2d,%d)->",p.pa[i].x,p.pa[i].y);
if((i+1)%(8+v)==0)
printf("\b\b\n->");
}
printf("\b\b\n");
}
(5)主函数:
voidmain()
提示输入起点位置,这里的起点位置就是日常生活观念中的顺序,开始点是(1,1),而不是数组中的初始位置(0,0),输入错误则提示重新输入,时间复杂度为。
voidmain()
{//主函数
intx,y,v;
charch='y’;
while(ch=='y')
{
printf("中国象棋马的遍历\n:
");
Mark_Che(v);
Mark_Dir(v);
while
(1)
{
printf("请输入入口点横坐标:
");
scanf("%d",&x);
if(x<1||x>8+2*v)
printf("输入错误,请重新输入!
(横坐标在1-%d
之间)\n",8+2*v);
else
break;
}
while
(1)
{
printf("请输入入口点纵坐标:
");
scanf("%d",&y);
if(y<1||y>8+v)
printf("输入错误,请重新输入!
(纵坐标在1-%d
之间)\n",8+v);
else
break;
}
Knight(x,y,v);
printf("是否继续?
继续:
y;");
fflush(stdin);
scanf("%c",&ch);
}
}
(6)棋盘初始化函数voidMark_Che(intv)
此函数作为棋盘初始化函数,因为每次执行程序时,棋盘上必须是全部都没有走过的。
它会自动进行初始化棋盘,在14*13的棋盘上初始化。
初始化后,棋盘大小的区域全部是0,而周围的两堵墙标志为1,时间复杂度为。
voidMark_Che(intv)
{//标志棋盘函数
inti,j;
for(i=0;i<12+2*v;i++)//首先全部标记为0
for(j=0;j<12+v;j++)
chessboard[i][j]=0;
for(i=0;i<2;i++)//前面两行标记为1
for(j=0;j<12+v;j++)
chessboard[i][j]=1;
for(j=0;j<2;j++)//前面两列标记为1
for(i=0;i<12+2*v;i++)
chessboard[i][j]=1;
for(j=10+v;j<12+v;j++)//后面两列标记为1
for(i=0;i<12+2*v;i++)
chessboard[i][j]=1;
for(i=10+2*v;i<12+2*v;i++)
for(j=0;j<12+v;j++)//后面两行标记为1
chessboard[i][j]=1;
}
(7)标记初始化函数voidMark_Dir(intv)
此函数和上面的函数功能类似,也是初始化才用,它是为栈的实现提供帮助的。
开始时全部标记为0,表示周围的八个方向都可以走,时间复杂度为。
voidMark_Dir(intv)
{//由于三维数组赋初值比较困难,因而采用单独的函数实现
inti,j,k;
for(i=0;i<12+2*v;i++)
for(j=0;j<12+v;j++)
for(k=0;k<8;k++)
CanPass[i][j][k]=0;
}
6.运行和测试:
程序运行开始时,提示用户输入入口横坐标,输入0,提示“输入错误,请重新输入!
(横坐标在1-10之间)”;再次输入1,提示输入纵坐标,输入10,提示“输入错误,请重新输入!
(纵坐标在1-9之间)”,再次输入2;出现结果,显示坐标形式;
运行结果如下图示:
7.心得体会:
通过这次课程设计,我体会到上机的重要性。
编写程序,离不开上机,一段不懂的代码只有经过反复的研读与调试,最终变成自己的代码。
一周的学习,让我学会一些知识,不在于学到了那么点技术,而在于心理得到了洗礼!
在此,我不说老师的功劳,也不提以前怎么怎么没好好听讲,没好好复习,没好好珍惜上机的机会。
最终我确实得到了锻炼,这就足够了!
对于接下来的路程,脚踏实地,勤奋努力比什么都重要;代码是枯燥的,但不枯燥的是学习的过程,难得的是学习过程中体会的快乐,有目标的学习与坚持,生活才会更加美好!
实验二.农夫过河
一.问题描述
设一个农夫过河带着一条狼、一只羊和一棵白菜,身处河的南岸。
现在他要把这些西全部运到北岸,现在问题是他面前只有一条小船,船小到只能容下他和一件物品,另外只有农夫能撑船。
当农夫在场的时候,这三样东西相安无事.一旦农夫不在,狼会吃羊,羊会吃白菜。
根据原题的描述我们知道,单独留下白菜和羊,或单独留下狼和羊在某一岸的状态是不安全的。
白菜和狼相处没事,把它看作个重要关系的,通过位置分布的代码来判断状态是否安全。
然后设计一个方案,模拟农夫能安全地将这三样东西带过河。
二.基本要求
以队列解决农夫过河问题,用广度优先搜索实现求解的过程。
用这个方法来搜索过程中总是首先搜索下面一步的所有可能状态,然后再进一步考虑更后面的各种情况。
要实现广度优先搜索,一般都采用队列作为辅助结构。
把下一步所有可能达到的状态都列举出来,放在这个队列中,然后顺序取出来分别进行处理,处理过程中把再下一步的状态放在队列里。
由于队列的操作遵循先进先出的原则,在这个处理过程中,只有在前一步的所有情况都处理完后,才能开始后面一步各情况的处理。
为了实现广度优先搜索,算法中需要使用了一个整数队列moveTo,它的每个元素表示一个可以安全到达的中间状态。
另外还需要一个数据结构记录已被访问过的各个状态,以及已被发现的能够到达当前这个状态的路径。
由于在这个问题的解决过程中需要列举的所有状态(二进制0000~1111)一共16种,所以可以构造一个包含16个元素的整数顺序表来满足以上的要求。
三.测试数据
要模拟农夫过河问题,首先需要选择一个对问题中每个角色的位置进行描述的方法。
一个很方便的办法是用四位二进制数顺序分别表示农夫、狼、白菜和羊的位置。
例如用0表示农夫或者某东西在河的南岸,1表示在河的北岸。
因此整数5(其二进制表示为0101)表示农夫和白菜在河的南岸,而狼和羊在北岸。
确定每个角色位置的函数,用整数location表示上述四位二进制描述的状态,用下面的四个函数从上述状态中得到每个角色所在位置的代码。
函数返回值为真表示所考察的人或物在河的北岸,否则在南岸。
从初始状态二进制0000(全部在河的南岸)出发,寻找一种全部由安全状态构成的状态序列,它以二进制1111(全部到达河的北岸)为最终目标,并且在序列中的每一个状态都可以从前一状态通过农夫(可以带一样东西)划船过河的动作到达。
五.源代码
//农夫过河问题
#include
#include
#defineMaxVertexNum10
typedefenum{FALSE,TRUE}Boolean;
Booleanvisited[MaxVertexNum];
intpath[MaxVertexNum];
typedefstruct{
intfarmer;
intwolf;
intsheep;
intvegetable;
}VertexType;
typedefstruct{
VertexTypevertexs[MaxVertexNum];
intedges[MaxVertexNum][MaxVertexNum];
intvertexNum,edgeNum;
}MGraph;
intlocate(MGraph*G,intF,intW,intS,intV)
{
inti;
for(i=0;i
if(G->vertexs[i].farmer==F&&G->vertexs[i].wolf==W&&
G->vertexs[i].sheep==S&&G->vertexs[i].vegetable==V)
returni;
return-1;
}
intis_safe(intF,intW,intS,intV)
{
if(F!
=S&&(W==S||S==V))return0;
elsereturn1;
}
intis_connected(MGraph*G,inti,intj)
{
intk=0;
if(G->vertexs[i].wolf!
=G->vertexs[j].wolf)k++;
if(G->vertexs[i].sheep!
=G->vertexs[j].sheep)k++;
if(G->vertexs[i].vegetable!
=G->vertexs[j].vegetable)k++;
if(G->vertexs[i].farmer!
=G->vertexs[j].farmer&&k<=1)
return1;
elsereturn0;
}
voidCreatG(MGraph*G)
{
inti,j,F,W,S,V;
i=0;
for(F=0;F<=1;F++)
for(W=0;W<=1;W++)
for(S=0;S<=1;S++)
for(V=0;V<=1;V++)
if(is_safe(F,W,S,V))
{G->vertexs[i].farmer=F;
G->vertexs[i].wolf=W;
G->vertexs[i].sheep=S;
G->vertexs[i].vegetable=V;
i++;
}
G->vertexNum=i;
for(i=0;i
for(j=0;j
if(is_connected(G,i,j))
G->edges[i][j]=G->edges[j][i]=1;
elseG->edges[i][j]=G->edges[j][i]=0;
return;
}
voidprint_path(MGraph*G,intu,intv)
{
intk;
k=u;
while(k!
=v)
{
printf("\n(%d,%d,%d,%d)",G->vertexs[k].farmer,G->vertexs[k].wolf,
G->vertexs[k].sheep,G->vertexs[k].vegetable);
k=path[k];
}
printf("\n(%d,%d,%d,%d)\n",G->vertexs[k].farmer,G->vertexs[k].wolf,
G->vertexs[k].sheep,G->vertexs[k].vegetable);
}
voidDFS_path(MGraph*G,intu,intv)
{
intj;
visited[u]=TRUE;
for(j=0;j
if(G->edges[u][j]&&!
visited[j]&&!
visited[v])
{path[u]=j;
DFS_path(G,j,v);
}
}
voidmain()
{
inti,j;
MGraphgraph;
CreatG(&graph);
for(i=0;i visited[i]=FALSE; i=locate(&graph,0,0,0,0); j=locate(&graph,1,1,1,1); DFS_path(&graph,i,j); printf("从左案到右岸。 0表示左岸,1表示右岸\n过河顺序为: \n(farmer,wolf,sheep,vegetable)"); if(visited[j]) print_path(&graph,i,j); } 六.运行结果 七.心得体会 对于农夫过河问题的设计,很明显突出了自己能力不足! 在这个过程中花费了大量时间找资料来弥补自己的缺乏的知识,自己对重新进得书本的学习,尽量使自己做得更! 从做课程设计的过程中,我的体会挺多的。 只要有信心与耐心,没有做不到的事情。 因为在这个过程中写代码与调试的过程中确实需要耐心与信心,否则就不可能写完整。 我也知道该课题还存在很多的漏洞,也不是很完整。 由于自己本身能力的原因,也不能使之更完整。 但是我已经尽我的努力写的了,同时在这些的设计中享受到了很多乐趣和知识
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 课程设计 206