数据结构课程设计报告.docx
《数据结构课程设计报告.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计报告.docx(14页珍藏版)》请在冰豆网上搜索。
数据结构课程设计报告
《数据结构》
课程设计报告
学号
119074258
姓名
黄芳恺
班级
软件工程114
指导教师
储岳中
安徽工业大学计算机学院
2013年6月
目录
一:
马的遍历问题
二:
大数相乘问题
一:
马的遍历问题
[程序设计名称]:
马的遍历
[程序设计要求]:
在中国象棋棋盘上,对任意位置上放置的一个马,均能选择一个合适的路线,使得该棋子能按象棋的规则不重复地走过棋盘上的每一位置。
主要要求:
依次输出所走过的各位置的坐标;最好能画出棋盘的图形形式,并在其上动态地标注行走过程。
[程序问题分析]:
先了解中国象棋的相关信息与规则。
中国象棋是9*10的棋盘,马的走法只有一种就是“马走日”,忽略“蹩脚马”的情况。
接着通过程序要求分析,这个题目采用的是深度优先算法和回溯法:
在“走到”一个位置后要寻找下一个位置,如果发生“阻塞”的情况,就是后面走不通的情况,则向后回溯,重新寻找。
在寻找下一步的时候,对周围的这几个点进行比较,从而分出优劣程度从而看它们周围可以走的点谁最少,然后就走那条可走路线最少的那条。
经过这样的筛选后,就会为后面的路径寻找提供方便,从而减少回溯次数。
最后,本程序的棋盘和数组类似,因而采用数组进行存储,同时因为有回溯,所以采用栈的方法。
同时还有八个方向的数组和为栈设计的每个点周围的八个方向那些可以走的数组。
[数据结构设计]:
棋盘有10行9列,利用chess来表示一个棋盘,chess[i][j]=0或1;其中:
0表示通路,1表示不通,当从某点向下试探时,中间点的8个方向可以试探;棋盘采用数组形式,并且这里的数组比棋盘的数组规模稍大,因为为了保证边缘点也有八个方向可以走,使问题能够简单化,不用再判断当前点的试探方向有几个。
栈(stack)是限定仅在表尾进行插入或删除操作的线性表。
因此,对栈来说,表尾端有特殊含义,称为栈顶(top),相应的,表头端称为栈底(bottom)。
不含元素的空表称为空栈。
假设栈S=(a1,a2,„,an),则称a1为栈底元素,an为栈顶元素。
栈的修改是按后进先出的原则进行的。
因此,栈又称为后进先出(List In First Out)的线性表。
在棋盘问题中,假设以栈S记录“当前路径”,则栈顶中存放的是“当前路径上最后一个通道块”。
由此,“纳入路径”的操作即为“当前位置入栈”;“从当前路径上删除前一通道块”的操作即为“出栈”。
1.同上面述,棋盘采用数组形式,并且这里的数组比棋盘的数组规模稍大,因为为了判断的方便,这里在棋盘周围各加了两层“墙”。
具体数据结构定义如下:
intchess[14][13];//采用最大的中国象棋10*9制的
intCanPath[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;//顺序栈
[数据功能设计]:
(1)计算一个点周围有几个点函数intCount(intx,inty)
该函数实现的功能是在遍历的过程当中计算一个点周围有几个方向可以走,从而为后面的筛选提供依据。
(2)寻找下一个方向函数intFind_Direction(intx,inty)
该函数的功能是在走过一个点之后,寻找下一个适合的点,如果找到返回正常的方向值,否则返回-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是拿出来的节点
(4)骑士遍历函数:
voidKnight(intx,inty,intv)
这是该算法的精华部分,x,y表示入口地点,v表示棋盘类型即中国象棋,这个函数主体是一个循环,循环里面始终是在找下一个点,如果找到就将该点进栈,找不到则退栈。
直到发生栈为空时退栈或循环结束,前一种情况时会提示找不到路径(虽然不会发生,但是为逻辑严密性依然要如此),后一种情况则打印出走过的正确路径和走过之后的数组
(5)主函数:
intmain()
提示输入起点位置,这里的起点位置就是日常生活观念中的顺序,开始点是(1,1),而不是数组中的初始位置(0,0),输入错误则提示重新输入
(6)棋盘初始化函数voidMark_Che(intv)
此函数作为棋盘初始化函数,因为每次执行程序时,棋盘上必须是全部都没有走过的。
它会自动进行初始化棋盘,在14*13的棋盘上初始化。
初始化后,棋盘大小的区域全部是0,而周围的两堵墙标志为1
(7)标记初始化函数voidMark_Dir(intv)
此函数和上面的函数功能类似,也是初始化才用,它是为栈的实现提供帮助的。
开始时全部标记为0,表示周围的八个方向都可以走
[程序设计代码]:
#include
#include
#include
intchess[14][13];//中国象棋9*10
intCanPath[14][13][8];//棋子的八个方向可以走d的
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;//顺序栈
intCount(intx,inty)
{//计算每个节点周围有几个方向可以走
intcount=0,i=0;
for(i=0;i<8;i++)
if(chess[x+1+dir[i].x][y+1+dir[i].y]==0)
count++;
returncount;
}
intFind_Direction(intx,inty)
{//寻找下一个方向
intdire,min=9,count,d=9;
for(dire=0;dire<8;dire++)
{
if(chess[x+1+dir[dire].x][y+1+dir[dire].y]==0&&CanPath[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;
}
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;
}
}
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)
{//正常找到下一个方向的情况下
chess[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&&chess[x+1][y+1]==0)
{//最后一次时t肯定是-1
chess[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;
CanPath[x+1][y+1][f.di]=1;
}
}
//根据栈中信息判断出马行走路径
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");
}
voidMark_Che(intv)
{//标志棋盘函数
inti,j;
for(i=0;i<12+2*v;i++)//首先全部标记为0
for(j=0;j<12+v;j++)
chess[i][j]=0;
for(i=0;i<2;i++)//前面两行标记为1
for(j=0;j<12+v;j++)
chess[i][j]=1;
for(j=0;j<2;j++)//前面两列标记为1
for(i=0;i<12+2*v;i++)
chess[i][j]=1;
for(j=10+v;j<12+v;j++)//后面两列标记为1
for(i=0;i<12+2*v;i++)
chess[i][j]=1;
for(i=10+2*v;i<12+2*v;i++)
for(j=0;j<12+v;j++)//后面两行标记为1
chess[i][j]=1;
}
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++)
CanPath[i][j][k]=0;
}
intmain()
{//主函数
intx,y,v=1;
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);
}
return0;
}
[程序运行结果]:
二:
大数相乘问题
[程序设计名称]:
大数相乘
[程序设计要求]:
大数相乘的问题主要是因为大数相乘其结果往往会超出数字类型的范围,所以不能简单用基础来考虑这个问题。
例如:
输入第一个数为:
132********172586,输入第二个数为:
2397567453241147则程序运行后输出13286754398172586*2397567453241147=正确答案。
[程序问题分析]:
首先考虑设计将两个大数按照输入顺序存入分别存入数组a[],b[]中;把这个数组中的每一位数字单独来进行乘法运算,比如我们可以用一个数字和另外一个数组中的每一位去相乘,从而得到乘法运算中一行的数字,再将每一行数字错位相加。
这就是乘法运算的过从低位往高位依次计算,同时确定每一列的项数,确定每一位上的结果存入数组c[]中;找到最高位在数组中的项c[i],然后依次输出各位上的数值;通过主函数来调用其它各个函数。
[数据结构设计]:
首先是输入阶段采用一维数组a[],b[]。
在输入阶段当大数输入时,大数a,b从高位到低位分别依次存入数组a[],b[];然后调用函数计算阶段采用一维数组c[]在调用sum(a,b,m,n)函数中,在计算过程中,由个位到高位依次计算各位的结果,并依次存入数组c[]中。
[数据功能设计]:
第一步找出每一列的所有项,即下标之和=m+n-2-i此限定条件可设计循环得出每一列的所有项。
接着计算从低位到高位每一位的值。
显然考虑到进位的问题,故必须从低位到高位依次计算,对于每一列,第一项可以除十取余数,保留在原位,存入c[],所得商进位存入mm。
然后对于第二列,第一项加进位mm,然后取余数存入su,再加第二项,取余数存入c[],求商存入进位mm,直到该列所有项参与运算到该列结束时,求的最终的c[],和mm.依次进行后面的运算。
最后找出反向存入结果c[]中的首项.因为最高位一定不为零,故可以设计程序从c[399]开始判断,当c[i]不等于零时,即为最高项。
[程序设计代码]:
#include
#include
voidS(intx[200],inty[200],intm,intn)//结果在数组里顺序是反着的
{
intmm=0;//保存进位
intc[400]={0};//保存结果
inti,j,s,tt;
for(i=0;i{
s=0;
for(j=0;j{
if((tt=(m-1+n-1-i-j))>=n||(tt=(m-1+n-1-i-j))<0)
continue;
else
s=s+x[j]*y[m-1+n-1-i-j];
}
s=s+mm;
c[i]=s%10;
mm=s/10;
}printf("结果:
\n");
for(i=399;i>=0;i--)//找首位
{
if(c[i]!
=0){
tt=i;break;
}
elsecontinue;
}
for(i=tt;i>=0;i--)//输出
printf("%d",c[i]);
printf("\n");
}
voidmain()
{
inti,m,n,c;
intx[200]={0},y[200]={0};
printf("输入第一个数字:
\n");
for(i=0;(c=getchar())!
='\n';i++)
x[i]=c-48;
m=i;
printf("输入第二个数字:
\n");
for(i=0;(c=getchar())!
='\n';i++)
y[i]=c-48;
n=i;//m,n为数字长度
S(x,y,m,n);
}
[程序运行结果]:
[设计实践过程中的心得体会]:
通过这次对《数据结构》课程设计的学习,在实验与实践过程中我学到了很多。
首先通过实践我掌握数据结构处理问题的基本思路和方法,我学会了如何根据相关要求进行上机调试,在不断实验中掌握了很多开发工具的运用。
总的来说,这次学习让我获益良多。
首先,我学会了在每次编程过程中必须要有个谨慎的心理。
对待每个问题必须认真对待,从问题的本质出发,先想应该怎么处理从哪里入手。
先对相关问题的要求进行解读,通过分析问题不断深入了解问题的本质。
在初步了解问题本质后,再开始分析一步一步的处理直至问题解决。
另外,在这次实验中,我对数据结构的整体有了新的认识,数据结构是计算机存储、组织数据的方式。
数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。
数据结构具体指同一类数据元素中,各元素之间的相互关系,包括三个组成成分,数据的逻辑结构,数据的存储结构和数据运算结构。
数据结构经常包括数组、栈、队列、链表、树、图等。
通过这次实验我对这些概念有了更深层次的认识。
通过这次修改与创新,我建立了新的认识,提高了我的系统性的认知能力,掌握从上而下的问题分析能力,既能理解各个类中方法的细节,又能站在项目总体的角度从宏观上认识程序,然后将程序很好地分解为不同功能的类。
不同的数据结构其操作集不同,但下列操作必不可缺:
1,结构的生成;2.结构的销毁;3,在结构中查找满足规定条件的数据元素;4,在结构中插入新的数据元素;5,删除结构中已经存在的数据元素;6,遍历。
另外,这次设计还巩固了我的C++等方面的知识。
在不断的测试运行中我不仅对基础语法的应用更加熟悉,在能力培养和技术训练,分析问题和解决问题的能力、表达能力有了更好的提升。
总体说来这次《数据结构》课程设计让我学会了很多,增强我们对未来的适应能力和解决问题的能力,更好地将理论联系实际。