C_栈的应用----迷宫求解

来源:互联网 发布:电脑软件学校招生 编辑:程序博客网 时间:2024/04/20 00:05

迷宫的描述:

用一个二维数组表示一个迷宫,这个二维数组的每一个元素的上下左右以及对角线上的四个方向,这总共加起来是八个方向,其中数字0表示可以通过,数字1表示此处不通,判断给定的一个迷宫是否有出路,有出路的话,求解出走出的路线。


用栈解决好处:
从入口出发,顺某一方向向前搜索,若能走通,则继续往前走;否则沿原路退回,换一个方向再继续搜索,直至所有可能的通路都搜索到位置。往前走就进栈,沿原路返回就出栈。


搜索一直切换向东邻方块,若走不通则新的位置为沿着顺时针旋转找到栈顶位置的下一相邻块。

测试数据左上角表示入口,右下角表示出口,若没有可走通路,那么输出“没有找到通路”,否则解出走出的路线。

网上找的一张图,左上角是入口,右下角是出口,别说还模拟挺像的。

测试数据:

0 0 1 0 0 0 1 0
0 0 1 0 0 0 1 0
0 0 0 0 1 1 0 0
0 1 1 1 0 0 0 0
0 0 0 1 0 0 0 0
0 1 0 0 0 1 0 0
0 1 1 1 0 1 1 0
1 0 0 0 0 0 0 0


输出结果:



迷宫中信息表示的意思可以用其他符号,代码我也是参考别人打着练习的=w=


栈的顺序存储操作:

typedef struct{int row;int col;}PosType;typedef struct{int step;//通道块在路径上的 序号PosType seat;//通道块在迷宫中的 坐标位置 int di; //从此通道块走向下一通道块的 方向 }SElemType; //栈的元素类型 typedef struct{SElemType*base;//栈底指针 SElemType*top;//栈顶指针 int stacksize;}SqStack;//栈的基本操作 


迷宫类型:

typedef struct{int m;int n;int arr[RANGE][RANGE];}MazeType;//迷宫类型 


具体操作代码如下:


求迷宫中一条从入口到出口的路径的算法可简单描述入下:


do{
  若当前位置可通:
  则{ 将当前位置插入栈顶;//纳入路径
  若该位置是出口位置,则结束;//求得路径存放在栈中
否则切换当前位置的东邻方块为新的当前位置; 
  } 
  否则,
  若栈不空且栈顶位置尚有其他方向未经探索,
  则设定新的当前位置为沿顺时针方向旋转找到的栈顶位置的下一相邻块;
若栈不空但栈顶位置的四周均不可通,
则{ 删去栈顶位置; 
若栈不空,则重新检测新的栈顶位置,
直到找到一个可通的相邻块或出栈至空栈; 

}while(栈不空);


代码实现:

Status MazePath(MazeType &maze,PosType start,PosType end){//求解迷宫maze中,从入口start到出口end的一条路径 //若存在,返回TRUR,否则返回FALSESqStack s;SElemType e;InitStack(s);PosType curpos=start;//设定当前位置为入口位置 int  curstep=1;//探索第一步do{if(Pass(maze,curpos)){//当前位置可以通过,即是未曾走到过的通道块 FootPrint(maze,curpos);//留下足迹  e=CreateSElem(curstep,curpos,1);//创建元素Push(s,e);//加入路径 if(PosEquare(curpos,end))return TRUE;//到达终点(出口) curpos=NextPos(curpos,1);//下一位置是当前位置的东邻curstep++;//探索下一步 }else{//当前位置不能通过 if(!StackEmpty(s)){Pop(s,e);while(e.di==4&&!StackEmpty(s)){MarkPrint(maze,e.seat);Pop(s,e);curstep--;//留下不能通过的标记,并且退回一步 }if(e.di<4){e.di++;Push(s,e);//换下一个方向探索curpos=NextPos(e.seat,e.di); } } }}while(!StackEmpty(s));return FALSE;}



在主函数输入迷宫信息,程序过程中帮迷宫四周加入围墙,表示只能在围墙内部进行搜索:

Status InitMaze(MazeType &maze,int a[][COL],int row,int col){//设置迷宫maze的初值,包括加上边缘一圈的值int i,j;//将迷宫外圈留出加上围墙的地方for(i=1;i<=row;i++)for(j=1;j<=col;j++)maze.arr[i][j]=a[i-1][j-1];//加上围墙for(j=0;j<=col+1;j++)maze.arr[0][j]=maze.arr[row+1][j]=1;for(i=0;i<=row+1;i++)maze.arr[i][0]=maze.arr[i][col+1]=1;maze.m=row;maze.n=col;return OK;}


判断当前结点是否可以通过,可以通过将该结点表示为1(TRUE)

当前位置可通,指的是未曾走到过的通道块,即要求该方块位置不仅是通道块,而且既不在当前路径上(否则所求路径就不是简单路径),也不是曾经纳入过路径的通道块:

Status Pass(MazeType maze,PosType curpos){//判断当前结点是否通过 return maze.arr[curpos.row][curpos.col]==0; }


对搜索过的结点留下足迹,' * '表示可以走通的路径:

StatusFootPrint(MazeType &maze,PosType curpos){//留下足迹 maze.arr[curpos.row][curpos.col]='*';return OK;}



对搜索过的结点留下足迹,'@'表示搜索过单但与出口无关的路径:

Status MarkPrint(MazeType &maze,PosType curpos){//留下不能通过的标记 maze.arr[curpos.row][curpos.col]='@';returnOK; }


设置迷宫信息:

SElemType CreateSElem(int step,PosType pos,int di){SElemType e;e.step=step;e.seat=pos;e.di=di;return e;}

返回当前结点的下一个结点:


PosType NextPos(PosType curpos,int di){//返回当前结点的下一个结点 PosType pos=curpos;switch(di){case 1://东pos.col++;break;case 2://南pos.row++;break;case 3://西 pos.col--;break;case 4://北 pos.row--;break; }return pos; }

判断结点是否相等:

Status PosEquare(PosType pos1,PosType pos2){return pos1.row==pos2.row&&pos1.col==pos2.col;}


输出迷宫信息:

void PrintMaze(MazeType maze,int row,int col){int i,j; for(i=1;i<=row;i++){for(j=1;j<=col;j++)switch(maze.arr[i][j]){case 0:printf("  ");//没有搜索过的路径 break;case 1:printf("# ");//表示障碍物 break;case '*':printf("* ");//走到终点的最优走发 break;case '@': printf("@ ");//搜素过但都不通的路径 break;}printf("\n");}}



嗯下面就是在VC中的测试:

#include<stdio.h>#include<stdlib.h>#include<string.h>#define OK 1#define ERROR 0#define TRUE 1#define FALSE 0#define OVERFLOW -2#define STACK_INIT_SIZE  100//存储空间初始化分配量#define STACKINCREMENT 10//存储空间分配增量 #define ElemType SElemType#define RANGE 100//迷宫大小#define ROW 8//迷宫的行数#define COL 8//迷宫的列数 typedef int Status;typedef struct{int row;int col;}PosType;typedef struct{int step;//通道块在路径上的 序号PosType seat;//通道块在迷宫中的 坐标位置 int di; //从此通道块走向下一通道块的 方向 }SElemType; //栈的元素类型 typedef struct{SElemType*base;//栈底指针 SElemType*top;//栈顶指针 int stacksize;}SqStack;//栈的基本操作 typedef struct{int m;int n;int arr[RANGE][RANGE];}MazeType;//迷宫类型 /*类型前置*/StatusInitMaze(MazeType &maze,int a[][COL],int row,int col);StatusPass(MazeType maze,PosType curpos);StatusFootPrint(MazeType &maze,PosType curpos);StatusMarkPrint(MazeType &maze,PosType curpos);SElemTypeCreateSElem(int step,PosType pos,int di);PosTypeNextPos(PosType curpos,int di);StatusPosEquare(PosType pos1,PosType pos2);void PrintMaze(MazeType maze,int row,int col);StatusMazePath(MazeType &maze,PosType start,PosType end);Status InitStack(SqStack &s){//构建一个空栈S。 s.base=(ElemType*)malloc(STACK_INIT_SIZE*(sizeof(SElemType)));if(!s.base){printf("建栈失败!\n");return ERROR; }else{s.top=s.base;//栈底和栈顶指针指向同一块内存 s.stacksize=STACK_INIT_SIZE;return OK; }}Status DestroyStack(SqStack &s){//销毁栈s,s不再存在。 s.top=s.base;free(s.base);s.base=NULL;//释放后一定要指向NULL,避免出现野指针 s.top=NULL;return OK;}Status ClearStack(SqStack &s){//将S清为空栈。 s.top=s.base;//栈顶和栈底指针指向同一块内存此时栈中就没有其它元素 s.stacksize=0;return OK;}Status StackEmpty(SqStack s){//若栈S为空栈,则返回TRUE,否则FALS。 if(s.top==s.base)return TRUE;elsereturn FALSE;}Status StackLength(SqStack s){//返回S的元素个数,即栈的长度.。 return s.top-s.base;}Status GetTop(SqStack s,ElemType &e){//用e返回S的栈顶元素 。 if(StackEmpty(s)){printf("这是一个空栈!");return ERROR;}else{s.top--;e=*s.top;return OK;}}Status Push(SqStack &s,SElemType e){//插入元素e为新的栈顶元素。if(StackLength(s)==STACK_INIT_SIZE){SElemType *temp=(SElemType*)realloc(s.base,(STACK_INIT_SIZE+STACKINCREMENT)*(sizeof(ElemType)));  if(!temp)return ERROR;s.base=temp;s.top=s.base+STACK_INIT_SIZE;s.stacksize=STACK_INIT_SIZE+STACKINCREMENT;*(s.top++)=e;return OK;}else{*s.top=e;s.top++;return OK; }}Status Pop(SqStack &s,SElemType &e){//删除S的栈顶元素,并用e返回其值if(StackEmpty(s)){//printf("这是一个空栈\n");return ERROR; }else{e=*(--s.top);return OK;}}Status InitMaze(MazeType &maze,int a[][COL],int row,int col){//设置迷宫maze的初值,包括加上边缘一圈的值int i,j;//将迷宫外圈留出加上围墙的地方for(i=1;i<=row;i++)for(j=1;j<=col;j++)maze.arr[i][j]=a[i-1][j-1];//加上围墙for(j=0;j<=col+1;j++)maze.arr[0][j]=maze.arr[row+1][j]=1;for(i=0;i<=row+1;i++)maze.arr[i][0]=maze.arr[i][col+1]=1;maze.m=row;maze.n=col;return OK;}Status Pass(MazeType maze,PosType curpos){//判断当前结点是否通过 return maze.arr[curpos.row][curpos.col]==0; }StatusFootPrint(MazeType &maze,PosType curpos){//留下足迹 maze.arr[curpos.row][curpos.col]='*';return OK;}Status MarkPrint(MazeType &maze,PosType curpos){//留下不能通过的标记 maze.arr[curpos.row][curpos.col]='@';returnOK; }SElemTypeCreateSElem(int step,PosType pos,int di){SElemType e;e.step=step;e.seat=pos;e.di=di;return e;}PosType NextPos(PosType curpos,int di){//返回当前结点的下一个结点 PosType pos=curpos;switch(di){case 1://东pos.col++;break;case 2://南pos.row++;break;case 3://西 pos.col--;break;case 4://北 pos.row--;break; }return pos; }Status PosEquare(PosType pos1,PosType pos2){//判断两结点是否相等 return pos1.row==pos2.row&&pos1.col==pos2.col;}void PrintMaze(MazeType maze,int row,int col){//打印迷宫信息int i,j; for(i=1;i<=row;i++){for(j=1;j<=col;j++)switch(maze.arr[i][j]){case 0:printf("  ");//没有搜索过的路径 break;case 1:printf("# ");//表示障碍物 break;case '*':printf("* ");//走到终点的最优走发 break;case '@': printf("@ ");//搜素过但都不通的路径 break;}printf("\n");}}Status MazePath(MazeType &maze,PosType start,PosType end){//求解迷宫maze中,从入口start到出口end的一条路径 //若存在,返回TRUR,否则返回FALSESqStack s;SElemType e;InitStack(s);PosType curpos=start;//设定当前位置为入口位置 int  curstep=1;//探索第一步do{if(Pass(maze,curpos)){//当前位置可以通过,即是未曾走到过的通道块 FootPrint(maze,curpos);//留下足迹  e=CreateSElem(curstep,curpos,1);//创建元素Push(s,e);//加入路径 if(PosEquare(curpos,end))return TRUE;//到达终点(出口) curpos=NextPos(curpos,1);//下一位置是当前位置的东邻curstep++;//探索下一步 }else{//当前位置不能通过 if(!StackEmpty(s)){Pop(s,e);while(e.di==4&&!StackEmpty(s)){MarkPrint(maze,e.seat);Pop(s,e);curstep--;//留下不能通过的标记,并且退回一步 }if(e.di<4){e.di++;Push(s,e);//换下一个方向探索curpos=NextPos(e.seat,e.di); } } }}while(!StackEmpty(s));return FALSE;}int main(){int a[ROW][COL]; printf("请输入要走的迷宫:\n"); for(int i=0;i<ROW;i++)for(int j=0; j<COL;j++) scanf("%d",&a[i][j]);PosType start,end; start.row = 1;start.col=1;//设置迷宫信息  end.row =ROW; end.col =COL; MazeType maze; InitMaze(maze,a,ROW,COL); printf("\n"); Status ok = MazePath(maze,start,end); if(ok)  PrintMaze(maze,ROW,COL);else printf("没有找到通路");return 0;}