数据结构程序的设计课题.docx
《数据结构程序的设计课题.docx》由会员分享,可在线阅读,更多相关《数据结构程序的设计课题.docx(29页珍藏版)》请在冰豆网上搜索。
![数据结构程序的设计课题.docx](https://file1.bdocx.com/fileroot1/2023-2/9/04191ad3-0b46-4ecc-b911-f9606c83faf4/04191ad3-0b46-4ecc-b911-f9606c83faf41.gif)
数据结构程序的设计课题
师学院
工科课程设计-《数据结构》
题目:
迷宫问题(栈)
学号:
1445013914450132
姓名:
鲁向阳肖吟月
班级:
物联网班(1405)
指导教师:
王杰老师
日期:
2016年6月
1概述
1.1课程设计目的
本次课程设计是迷宫求解问题,主要是模拟从入口到出口的通路。
程序中的数据采取的是“栈”作为数据的逻辑结构,并且使用链式存储结构,即是实现一个以链表作存储结构的栈类型。
本课程设计实现了链栈的建立,入栈,出栈,判断栈是否为空的方法,关键的是迷宫通路路径的“穷举求解”和递归求解的方法。
1.2开发环境
具有Intel酷睿i3处理器且满足以下要求的计算机:
4GB存,500GB硬盘;安装VisualC++6.0。
1.3任务分配
两人一起查找相关资料,整合并进行探讨。
其中一人通过查找的资料先行拟定文件的大纲,初步定稿后,然后再由另一个人进行进一步加工,细化,最后两人一起核实文件,进行进一步的升华,最终完成该任务。
2需求分析
2.1题目容
以一个m*n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。
设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论。
2.2设计思想说明
计算机解迷宫通常用的是“穷举求解”方法,首先从迷宫的入口开始,如果该位置就是迷宫出口,则已经找到了一条路径,搜索工作结束。
否则从入口出发,顺着某个方向进行探索,若能走通,则继续往前进,否则沿着原路退回,换一个方向继续探索,直至出口位置,求得一条通路。
假如所有可能的通路都探索到而未能到达出口,则所设的迷宫没有通路。
可以用二维数组存储迷宫数据,通常设定入口点的下标为(1,1),出口点的下标为(n,n)。
为处理方便起见,可在迷宫的四周加一圈障碍。
对于迷宫中任一位置均可约定有东、南、西、北四个方向可通。
要实现上述算法,需要用到栈的思想。
栈里面压的是走过的路径,若遇到死路,则将该位置在栈的顶层)弹出,再进行下一次判断;若遇到通路,则将该位置压栈并进行下一次判断。
如此反复循环,直到程序结束。
此时,若迷宫有通路,则栈中存储的是迷宫通路坐标的倒序排列,再把所有坐标顺序排列好后,即可得到正确的迷宫通路。
2.3数据结构设计
(1)以一个m*n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。
迷宫的四周有一圈障碍。
(2)程序输出的结果以三元组(i,j,di)的形式输出,其中:
(i,j)指示迷宫中的一个坐标,di表示走到下一坐标的方向,di的取值为0、1、2、3分别表示北、东、南、西。
(3)若设定的迷宫存在通路,则以方阵形式将迷宫及其通路输出到标准输出文件上,对于迷宫中的每个方块,有上下左右4个方块相邻,第i行第j列的当前方块的位置记为(i,j),规定上方方块为方位0,并按顺时针方向递增编号。
在试探过程中,假设按从方位0到方位3的顺序查找下一个可走的方块。
(4)先将入口进栈(其初始方位设置为-1),在栈不空时循环:
取栈顶方块(不退栈),若该方块是出口,则输出栈中所有方块即为路径,否则,找下一个可走的相邻方块,若不存在这样的方块,说明当前路径不可能走通,则回溯。
也就是恢复当前方块为0后退栈;若存在这样的方块,则将这个可走的相邻方块进栈(其初始方位设置为-1)。
3算法的设计
3.1定义坐标(X,Y)
#include
#include
usingnamespacestd;
structCoor
{
introw;
intcolumn;
intdirection;
};
3.2定义方向
structMove
{
introw;
intcolumn;
};
3.3定义/链表结点
structLinkNode
{
Coordata;
LinkNode*next;
};
3.4定义栈
classstack
{
private:
LinkNode*top;
public:
stack();
~stack();
voidPush(Coordata);
CoorPop();
CoorGetPop();
voidClear();
boolIsEmpty();
};
3.5定义迷宫定义移动的4个方向
Movemove[4]={{0,1},{1,0},{0,-1},{-1,0}};
6、几个函数功能的描述:
stack();//构造函数,置空栈
~stack();//析构函数
voidPush(Coordata);//把元素data压入栈中
CoorPop();//使栈顶元素出栈
CoorGetPop();//取出栈顶元素
voidClear();//把栈清空
boolIsEmpty();//判断栈是否为空
boolMazepath(int**maze,intm,intn);
//寻找迷宫maze中从(0,0)到(m,n)的路径
//到则返回true,否则返回false
voidPrintPath(stackp);//输出迷宫的路径
voidPrintPath2(intm,intn,stackp,int**maze);//输出路径
voidRestore(int**maze,intm,intn);//恢复迷
4各模块的伪码算法
4.1根据输入产生一个8*8的迷宫
m=a;
n=b;
maze=newint*[m+2];//申请长度等于行数加2的二级指针
for(i=0;i{
maze[i]=newint[n+2];
}
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
cin>>maze[i][j];
cout<<"是否保存新迷宫?
\n";
cout<<"用Y或y表示保存、N或n表示不保存\n";
charchoose;
cin>>choose;
if(choose=='Y'||choose=='y')
{
charch;
ofstreamfop("Newtest.txt");
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
ch='0'+maze[i][j];
fop<}
fop<flush(cout);
}
fop.close();
}
}
//给迷宫的四周加一堵墙,即把迷宫四周定义为1
for(i=0;imaze[i][0]=maze[i][n+1]=1;
for(i=0;imaze[0][i]=maze[m+1][i]=1;
for(intp=0;p{
for(intq=0;q<=n+2;++q)
{
if(maze[p][q]==0)
cout<<"■";
if(maze[p][q]>=1)
cout<<"□";
}
cout<}
returnmaze;//返回存贮迷宫的二维指针maze
4.2探索路径函数
boolMazepath(int**maze,intm,intn)
//寻找迷宫maze中从(0,0)到(m,n)的路径
//到则返回true,否则返回false
{
stackq,p;//定义栈p、q,分别存探索迷宫的存储和路径过程
CoorTemp1,Temp2;
introw,column,loop;
Temp1.row=1;
Temp1.column=1;
q.Push(Temp1);//将入口位置入栈
p.Push(Temp1);
maze[1][1]=8;//标志入口位置已到达过
while(!
q.IsEmpty())//栈q非空,则反复探索
{
Temp2=q.GetPop();//获取栈顶元素
if(!
(p.GetPop().row==q.GetPop().row&&p.GetPop().column==q.GetPop().column))
p.Push(Temp2);
//如果有新位置入栈,则把上一个探索的位置存入栈p
for(loop=0;loop<4;loop++)//探索当前位置的4个相邻位置
{
row=Temp2.row+move[loop].row;//计算出新位置x位置值
column=Temp2.column+move[loop].column;//计算出新位置y位置值
if(maze[row][column]==0)//判断新位置是否可达
{
Temp1.row=row;
Temp1.column=column;
maze[row][column]=8;//标志新位置已到达过
q.Push(Temp1);//新位置入栈
}
if((row==(m))&&(column==(n)))//成功到达出口
{
Temp1.row=m;
Temp1.column=n;
Temp1.direction=0;
p.Push(Temp1);//把最后一个位置入栈
charchoose;
cout<<"请选择以坐标形式(row,column,direction)输出迷宫选
(1)或以方阵形式输出迷宫选
(2):
";
cin>>choose;
if(choose=='1')
{
PrintPath(p);//坐标显示输出
Restore(maze,m,n);
}
else
{
PrintPath2(m,n,p,maze);//矩阵显示输出
Restore(maze,m,n);
}
return1;//表示成功找到路径
}
}
if(p.GetPop().row==q.GetPop().row&&p.GetPop().column==q.GetPop().column)
//如果没有新位置入栈,则返回到上一个位置
{
p.Pop();
q.Pop();
}
}
return0;//表示查找失败,即迷宫无路经
}
4.3输出迷宫
voidPrintPath(stackp)//输出路径
{
cout<<"迷宫的路径为\n";
cout<<"括号的容分别表示为(行坐标,列坐标,数字化方向,方向)\n";
stackt;//定义一个栈,按从入口到出口存取路径
inta,b;
Coordata;
LinkNode*temp;
temp=newLinkNode;//申请空间
temp->data=p.Pop();//取栈p的顶点元素,即第一个位置
t.Push(temp->data);//第一个位置入栈t
deletetemp;//释放空间
while(!
p.IsEmpty())//栈p非空,则反复转移
{
temp=newLinkNode;
temp->data=p.Pop();//获取下一个位置
//得到行走方向
a=t.GetPop().row-temp->data.row;//行坐标方向
b=t.GetPop().column-temp->data.column;//列坐标方向
if(a==1)temp->data.direction=1;//方向向下,用1表示
elseif(b==1)temp->data.direction=2;//方向向右,用2表示
elseif(a==-1)temp->data.direction=3;//方向向上,用3表示
elseif(b==-1)temp->data.direction=4;//方向向左,用4表示
t.Push(temp->data);//把新位置入栈
deletetemp;
}
cout<<"坐标(row,column,direction)中x在指向当前位置所在的行数,y指向当前位置所在的列数,";
cout<<"direction表示下一位置走向。
"<//输出路径,包括行坐标,列坐标,下一个位置方向
while(!
t.IsEmpty())//栈非空,继续输出
{
data=t.Pop();
cout<<'('<switch(data.direction)//输出相应的方向
{
case1:
cout<<"↓)\n";break;
case2:
cout<<"→)\n";break;
case3:
cout<<"↑)\n";break;
case4:
cout<<"←)\n";break;
case0:
cout<<")\n";break;
}
}
}
voidPrintPath2(intm,intn,stackp,int**maze)//输出路径
{
cout<<"迷宫的路径为\n";
for(inti=0;i{
for(intj=0;jcout<cout<}
}
5函数的调用关系图
6测试结果
6.1自动生成迷宫运行情况
(1)选择生成迷宫输入1如下图所示
(2)选择以坐标形式输出迷宫:
7心得体会
通过这段时间的课程设计,本人对计算机的应用,数据结构的作用以及C语言的使用都有了更深的了解。
尤其是C语言的进步让我深刻的感受到任何所学的知识都需要实践,没有实践就无法真正理解这些知识以及掌握它们,使其成为自己的财富。
在设计此程序时,刚开始感到比较迷茫,然后一步步分析,试着写出基本的算法,思路渐渐清晰,最后完成程序。
当然也遇到不少的问题,也正是因为这些问题引发的思考给我带了收获。
在遇到描写迷宫路径的算法时,我感到有些困难,后来经过一步步分析和借鉴书本上的穷举求解的算法,最后把算法写出来。
在利用递归方法求路径时花费了我很长时间,由于本人对递归方面的知识运用较少,导致我不熟悉它的用法,但最终还是通过询问同学、查找书本和上网了解关于递归方面的知识写出来了。
这次课程设计让我更加深入了解很多方面的知识,如链结构的栈类型及其基本操作,数组的运用等等。
在程序的编写中不要一味的模仿,要自己去摸索,只有带着问题反复实践,才能熟练地掌握和运用。
在实际的上机操作过程中,不仅是让我们了解数据结构的理论知识,更重要的是培养解决实际问题的能力,所以相信通过此次实习可以提高我们分析设计能力和编程能力,为后续课程的学习及实践打下良好的基础。
参考文献
[1]严蔚敏、吴伟民:
《数据结构(C语言版)》[M],清华大学2007年版
[2]谭浩强:
《C语言设计(第三版)》[M],清华大学2005年版
[3]衍龙、林瑞仲、徐慧:
《C语言实例解析精粹(第二版)》[M],人民邮电
附录
#include
#include
usingnamespacestd;
structCoor//定义描当前位置的结构类型
{
introw;
intcolumn;
intdirection;
};
structMove//定义下一个位置的方向
{
introw;
intcolumn;
};
structLinkNode//链表结点
{
Coordata;
LinkNode*next;
};
//定义栈
classstack
{
private:
LinkNode*top;
public:
stack();//构造函数,置空栈
~stack();//析构函数
voidPush(Coordata);//把元素data压入栈中
CoorPop();//使栈顶元素出栈
CoorGetPop();//取出栈顶元素
voidClear();//把栈清空
boolIsEmpty();//判断栈是否为空
};
stack:
:
stack()//构造函数,置空栈
{
top=NULL;
}
stack:
:
~stack()//析构函数
{
}
voidstack:
:
Push(Coorx)//把元素data压入栈中
{
LinkNode*TempNode;
TempNode=newLinkNode;
TempNode->data=x;
TempNode->next=top;
top=TempNode;
}
Coorstack:
:
Pop()//使栈顶元素出栈
{
CoorTemp;
LinkNode*TempNode;
TempNode=top;
top=top->next;
Temp=TempNode->data;
deleteTempNode;
returnTemp;
}
Coorstack:
:
GetPop()//取出栈顶元素
{
returntop->data;
}
voidstack:
:
Clear()//把栈清空
{
top=NULL;
}
boolstack:
:
IsEmpty()
{
if(top==NULL)
returntrue;
else
returnfalse;
}
Movemove[4]={{0,1},{1,0},{0,-1},{-1,0}};//定义移动的4个方向
boolMazepath(int**maze,intm,intn);
//寻找迷宫maze中从(0,0)到(m,n)的路径
//到则返回true,否则返回false
voidPrintPath(stackp);//输出迷宫的路径
voidPrintPath2(intm,intn,stackp,int**maze);//输出路径
voidRestore(int**maze,intm,intn);//恢复迷宫
int**GetMaze(int&m,int&n);//获取迷宫(可从文件中读取,也可输入)
//返回存取迷宫的二维指针
intmain()
{
system("colorf5");
intm=0,n=0;
int**maze;//定义二维指针存取迷宫
cout<<"\n\t\t****************欢迎使用迷宫模拟程序*************"<cout<<"\t\t14级计算机物联网班"<cout<<"\t\t鲁向阳肖吟月"<cout<<"\t\t学号:
1445013914450132"<maze=GetMaze(m,n);//调用GetMaze(int&m,int&n)函数,得到迷宫
if(Mazepath(maze,m,n))//调用Mazepath(int**maze,intm,intn)函数获取路径
cout<<"迷宫路径探索成功!
\n";
elsecout<<"路径不存在!
\n";
return0;
}
int**GetMaze(int&m,int&n)
//获取迷宫(可从文件中读取,也可输入)
//返回存取迷宫的二维指针
{
int**maze;
inti=0,j=0;
charChoose;//定义一个标志,选择读取文件或直接输入,获取迷宫
cout<<"请选择生成
(1)或键盘输入
(2):
";
cin>>Choose;
if(Choose=='1')//当标志Choose为‘1’时,读取文件
{
cout<<"生成迷宫如下:
\n";
charch;//定义一个字符,读取文件中的容
i=0,j=0;
//首先得到文件中数字字符的数目,并得到迷宫的长和宽
ifstreamfip("test.txt");
//定义一个文件对象,并打开文件“test.txt”
while(fip.get(ch))//从读取文件中容(一个个字符)
{
if(ch>='0'&&ch<='9')//获取文件中的数字字符
{
j++;//如果是字符,列就加1
}
if(ch=='\n')
{
i++;//如果是换行,就行加1
n=j;//得到宽,即列数
j=0;
}
}
fip.close();//读取文件结束
m=i;//得到长即行数
maze=newint*[m+2];//申请长度等于行数加2的二级指针
for(i=0;i{
maze[i]=newint[n+2];
}
i=j=1;
ifstreamfip2("test.txt");//重新读取文件,以得到容
while(fip2.get(ch))
{
if(ch>='0'&&ch<='9')
{
maze[i][j]=ch-'0';//把数字字符转化为数字,并存到指针里
cout<j++;
}
if(ch=='\n')//遇到换行,指针也相应换行
{
cout<i++;
j=1;
}
}
fip2.close();//读取结束
cout<}
else//Choose=2,输入迷宫
{
cout<<"请输入迷宫的行数和列数:
(中间用空格键分开)";
inta,b;
cin>>a>>b;
cout<<"请输入迷宫容:
(0表示通路,1表示不连通。
中间用空格键分开)\n";
m=a;
n=b;
maze=newint*[m+2];//申请长度等于行