您的位置:首页 > 理论基础 > 数据结构算法

10、数据结构笔记之十栈的应用之迷宫求解实现

2017-09-10 15:42 471 查看
10、数据结构笔记之十栈的应用之迷宫求解实现
           “人生是伟大的宝藏,我晓得从这个宝藏里选取最珍贵的珠宝。

           继续栈的应用,这次实现迷宫求解。

1.  迷宫求解

计算机解迷宫时,通常是用穷举求解,从入口出发,顺某个方向向前探索,通则往前,不通则返回。显然是不要一个后进先出的饥饿哦股来保存从入口到当前位置的路径。

算法描述:

设定当前位置的初值为入口位置:

Do{

           若当前位置可通,

则{  将当前位置插入栈顶;

               若该位置是出口位置,则结束

                     否则切换当前位置的东邻方块为新的当前位置;

                      }

否则,

                      若 栈不空且栈顶位置尚有其他方向未经探索,

                      则设定新的当前位置为沿顺时针方向旋转找到的栈顶位置的下一组邻块;

                      若栈不空但栈顶位置的四周均不可通,

                      则{

                               删去栈顶位置;

                                 若栈不空,则重新测试新的栈顶位置。

                                 直至找到一个可通的相邻块或出栈至栈空;

}

}while(栈不空)

 

 

2.  建立迷宫

代码如下,定义结构体PostType表示迷宫中的r行c列的位置。

定义结构体MazeType,表示迷宫类型。

函数InitMaze来实现对迷宫的初始化。

typedefstruct{      

           intr;
//迷宫中r行c列的位置
           intc;
}PostType;
 
#defineMAXLEN10//迷宫包括外墙最大行列数目
typedefstruct{
           intr;
           intc;
           charadr[MAXLEN][MAXLEN];
}MazeType;  
//迷宫类型
Status InitMaze(MazeType&maze){
//初始化迷宫,把初始化改为输入就能够进行动态建立迷宫
           inti,j;       

           maze.r=8;maze.c=8;//迷宫行和列数
           for(i=0;i<10;i++){//迷宫行外墙
                     maze.adr[0][i]='#';
                     maze.adr[9][i]='#';
           }
           for(i=0;i<10;i++){//迷宫列外墙
                     maze.adr[i][0]='#';
                     maze.adr[i][9]='#';
           }
           for(i=1;i<9;i++)
                     for(j=1;j<9;j++)
                               
maze.adr[i][j]=1;//初始化迷宫
           //设定通道块上的不通的路块
           maze.adr[1][3]='#';maze.adr[1][7]='#';maze.adr[2][3]='#';maze.adr[2][7]='#';maze.adr[3][5]='#';maze.adr[3][6]
 
           ='#';
           maze.adr[4][2]='#';maze.adr[4][3]='#';maze.adr[4][4]='#';maze.adr[5][4]='#';maze.adr[6][2]='#';maze.adr[6][6]
 
           ='#';
           maze.adr[7][2]='#';maze.adr[7][3]='#';maze.adr[7][4]='#';maze.adr[7][6]='#';maze.adr[7][7]='#';maze.adr[8][1]
 
           ='#';
           returnOK;
}//InitMaze       

 

 

3.  打印迷宫

void PrintMaze(MazeType *maze){//
           inti,j;
           printf("用心形代表迷宫的从入口到出口的一条路径\n");
           printf("用#代表墙和不通的地方用@代表曾走过的通道块但不通\n");
           printf("用笑脸代表可以通过的通道块\n");
           printf("  ");
           for(i=0;i<10;i++)//打印列数名
                     printf("%2d",i);
           printf("\n");
           for(i=0;i<10;i++){
                     printf("%2d",i);//打印行名
                     for(j=0;j<10;j++)
                                printf("%2c",maze->adr[i][j]);//输出迷宫//当前位置的标记         

                     printf("\n");
           }
           printf("通道块坐标:");
           for(i=0;i<10;i++)
                     for(j=0;j<10;j++)
                               
if(maze->adr[i][j]==3)
                                          printf("(%d,%d)",i,j);
}//PrintMaze

 

输入如下如图1

 

4.  迷宫算法

根据第一节出的迷宫求解简单算法,通过C实现如下:

Status MazePath(MazeType *maze,PostTypestart,PostTypeend){
           //迷宫maze存在从入口start到end的通道则求得一条存放在栈中
           StackS;
           PostTypecurpos;
           intcurstep;//当前序号,1.2.3.4分别表示东,南,西,北方向
           SElemTypee;
           InitStack(&S);
           curpos=start;
//设置"当前位置"为"入口位置"
           curstep=1;   //探索第一步
           do{  

                     if(Pass(maze,curpos)){    
//当前位置可以通过,
                                FootPrint(maze,curpos);//留下足迹
                                e.ord=curstep;
                                e.seat=curpos;
                                e.di=1;
                                Push(&S,e);             
//加入路径
                               
if(curpos.r==end.r&&curpos.c==end.c)
                                         
return1;
//到达出口            

                                curpos=NextPos(&curpos,1);//下一位置是当前位置的东邻
                                curstep++;      
//探索下一步                            
                     }
                     else{       
//当前位置不通
                               
if(!StackEmpty(&S)){       

                                          e= Pop(&S);
                                         
while(e.di==4&& !StackEmpty(&S)){
                                                     MarkPrint(maze,e.seat);
                                                     e=Pop(&S);        
//留下不能通过的标记,并退一步
                                          }//while
                                         
if(e.di< 4){
                                                     e.di++;//换下一个方向探索
                                                     Push(&S,e);           

                                                     curpos=NextPos(&e.seat,e.di);//设定当前位置是该新方向上的相邻
                                          }
                                }
                     }
           }while(!StackEmpty(&S));
           return1;
}//MazePath

5.  Main函数

Main函数如下图所示:

void main(){    
//主函数
           MazeTypemaze;
           PostTypestart,end;
           InitMaze(&maze);//初始化并创建迷宫
           start.r=1;start.c=1;//迷宫入口坐标
           end.c=8;end.r=8;//迷宫出口坐标
           PrintMaze(&maze);
           MazePath(&maze,start,end);
           PrintMaze(&maze);//打印路径
}

 

6.  源码

#include<stdio.h>
#include<stdlib.h>
 
 
 
#defineINIT_SIZE100
//存储空间初始分配量
#defineINCREMENT10 
//存储空间分配增量
#defineMAXLEN10//迷宫包括外墙最大行列数目
 
typedefintStatus;
typedefstruct{      

           intr;
//迷宫中r行c列的位置
           intc;
}PostType;
 
 
typedefstruct{
           intr;
           intc;
           charadr[MAXLEN][MAXLEN];
}MazeType;  
//迷宫类型
 
 
 
typedefstruct{
           int  ord;     //当前位置在路径上的序号
           PostTypeseat;//当前坐标
           int  di;      //往下一坐标的方向
}SElemType;       
//栈内元素类型
typedefstruct{
           SElemType*base;
           SElemType*top;
           intstackSize;
}Stack;            
//栈类型
Status InitMaze(MazeType *maze){//初始化迷宫,把初始化改为输入就能够进行动态建立迷宫
           inti,j;       

           maze->r=8;
           maze->c=8;//迷宫行和列数
           for(i=0;i<10;i++){//迷宫行外墙
                     maze->adr[0][i]='#';
                     maze->adr[9][i]='#';
           }
           for(i=0;i<10;i++){//迷宫列外墙
                     maze->adr[i][0]='#';
                     maze->adr[i][9]='#';
           }
           for(i=1;i<9;i++)
                     for(j=1;j<9;j++)
                               
maze->adr[i][j]=1;
           //初始化迷宫
 
           //设定通道块上的不通的路块
           maze->adr[1][3]='#';
           maze->adr[1][7]='#';
           maze->adr[2][3]='#';
           maze->adr[2][7]='#';
           maze->adr[3][5]='#';
           maze->adr[3][6]='#';
           maze->adr[4][2]='#';
           maze->adr[4][3]='#';
           maze->adr[4][4]='#';
           maze->adr[5][4]='#';
           maze->adr[6][2]='#';
           maze->adr[6][6]='#';
           maze->adr[7][2]='#';
           maze->adr[7][3]='#';
           maze->adr[7][4]='#';
           maze->adr[7][6]='#';
           maze->adr[7][7]='#';
           maze->adr[8][1]='#';
           return1;
}//InitMaze
 
 
Status InitStack(Stack *S){ 
//构造空栈S
           S->base=(SElemType*)malloc(INIT_SIZE
*sizeof(SElemType));
           if(!S->base)
                     exit(-1);//存储分配失败
           S->top=S->base;
           S->stackSize=INIT_SIZE;
           return1;
}//InitStack
 
Status StackEmpty(Stack *S)
{
           if(S->top==S->base)
                     return1;
           else
                     return0;
}
 
Status Push(Stack *S,SElemTypee)
{
           //插入元素e为新的栈顶元素
           if(S->top-S->base>=S->stackSize){//栈满,加空间
                     S->base=(SElemType*)realloc(S->base,(S->stackSize+INCREMENT)*sizeof(SElemType));
                     if(!S->base)
                                exit(-1);  
//存储分配失败
                     S->top=S->base+S->stackSize;
                     S->stackSize+=INCREMENT;
           }
           *S->top++=e;
           return1;
}//push
 
SElemType Pop(Stack *S)
{
           //若栈不空删除栈顶元素用e返回并返回OK,否则返回ERROR
           SElemTypee;
           e=*--S->top;
           returne;
}//Pop
 
 
 
Status Pass(MazeType *maze,PostTypecurpos){
           //判断当前位置是否可通
           if(maze->adr[curpos.r][curpos.c]==1)//可通
                     return1;
           else
                     return0;
}//Pass
 
Status FootPrint(MazeType *maze,PostTypecurpos){
           //走过并且可通
           maze->adr[curpos.r][curpos.c]=3;//"*"表示可通
           return1;
}//FootPrint
 
 
PostType NextPos(PostType *curpos,inti){
           //探索下一位置并返回下一位置的坐标
           PostType*cpos;
           cpos=curpos;
           //1.2.3.4分别表示东,南,西,北方向
           switch(i){
           case 1: cpos->c+=1;
break;
           case 2: cpos->r+=1;
break;
           case 3: cpos->c-=1;
break;
           case 4: cpos->r-=1;
break;
           default:exit(-1); 

           }
           return*cpos;
}//Nextpos
 
 
Status MarkPrint(MazeType *maze,PostTypecurpos){
           //曾走过但不通留下标记并返回OK
           maze->adr[curpos.r][curpos.c]='@';//"@"表示曾走过但不通
           return1;
}//MarkPrint
 
 
 
 
Status MazePath(MazeType *maze,PostTypestart,PostTypeend){
           //迷宫maze存在从入口start到end的通道则求得一条存放在栈中
           StackS;
           PostTypecurpos;
           intcurstep;//当前序号,1.2.3.4分别表示东,南,西,北方向
           SElemTypee;
           InitStack(&S);
           curpos=start;
//设置"当前位置"为"入口位置"
           curstep=1;   //探索第一步
           do{  

                     if(Pass(maze,curpos)){    
//当前位置可以通过,
                                FootPrint(maze,curpos);//留下足迹
                                e.ord=curstep;
                                e.seat=curpos;
                                e.di=1;
                                Push(&S,e);             
//加入路径
                               
if(curpos.r==end.r&&curpos.c==end.c)
                                         
return1;
//到达出口            

                                curpos=NextPos(&curpos,1);//下一位置是当前位置的东邻
                                curstep++;      
//探索下一步                           

                     }
                     else{       
//当前位置不通
                               
if(!StackEmpty(&S)){       

                                          e= Pop(&S);
                                         
while(e.di==4&& !StackEmpty(&S)){
                                                     MarkPrint(maze,e.seat);
                                                     e=Pop(&S);        
//留下不能通过的标记,并退一步
                                          }//while
                                         
if(e.di< 4){
                                                     e.di++;//换下一个方向探索
                                                     Push(&S,e);           

                                                     curpos=NextPos(&e.seat,e.di);//设定当前位置是该新方向上的相邻
                                          }
                                }
                     }
           }while(!StackEmpty(&S));
           return1;
}//MazePath
 
 
void PrintMaze(MazeType *maze){//
           inti,j;
           printf("用心形代表迷宫的从入口到出口的一条路径\n");
           printf("用#代表墙和不通的地方用@代表曾走过的通道块但不通\n");
           printf("用笑脸代表可以通过的通道块\n");
           printf("  ");
           for(i=0;i<10;i++)//打印列数名
                     printf("%2d",i);
           printf("\n");
           for(i=0;i<10;i++){
                     printf("%2d",i);//打印行名
                     for(j=0;j<10;j++)
                                printf("%2c",maze->adr[i][j]);//输出迷宫//当前位置的标记         

                     printf("\n");
           }
           printf("通道块坐标:");
           for(i=0;i<10;i++)
                     for(j=0;j<10;j++)
                               
if(maze->adr[i][j]==3)
                                          printf("(%d,%d)",i,j);
}//PrintMaze
 
 
void main(){    
//主函数
           MazeTypemaze;
           PostTypestart,end;
           InitMaze(&maze);//初始化并创建迷宫
           start.r=1;start.c=1;//迷宫入口坐标
           end.c=8;end.r=8;//迷宫出口坐标
           PrintMaze(&maze);
           MazePath(&maze,start,end);
           PrintMaze(&maze);//打印路径
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: