10、数据结构笔记之十栈的应用之迷宫求解实现
2017-09-10 15:42
471 查看
10、数据结构笔记之十栈的应用之迷宫求解实现
“人生是伟大的宝藏,我晓得从这个宝藏里选取最珍贵的珠宝。”
继续栈的应用,这次实现迷宫求解。
算法描述:
设定当前位置的初值为入口位置:
Do{
若当前位置可通,
则{ 将当前位置插入栈顶;
若该位置是出口位置,则结束
否则切换当前位置的东邻方块为新的当前位置;
}
否则,
若 栈不空且栈顶位置尚有其他方向未经探索,
则设定新的当前位置为沿顺时针方向旋转找到的栈顶位置的下一组邻块;
若栈不空但栈顶位置的四周均不可通,
则{
删去栈顶位置;
若栈不空,则重新测试新的栈顶位置。
直至找到一个可通的相邻块或出栈至栈空;
}
}while(栈不空)
定义结构体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
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
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 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);//打印路径
}
#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);//打印路径
}
“人生是伟大的宝藏,我晓得从这个宝藏里选取最珍贵的珠宝。”
继续栈的应用,这次实现迷宫求解。
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);//打印路径
}
相关文章推荐
- 11、数据结构笔记之十一栈的应用之表达式求值实现
- 算法:迷宫求解(栈的应用)-数据结构(8)
- 数据结构之栈的应用----迷宫求解
- (5)数据结构——栈应用——迷宫求解
- C语言 数据结构中求解迷宫问题实现方法
- 数据结构与算法学习笔记——堆栈及其应用(10以内简单四则计算器)
- 数据结构(7)—栈的应用之迷宫求解
- 数据结构之栈的应用----迷宫求解
- 看数据结构写代码(13)栈的应用(四) 迷宫求解
- 12、数据结构笔记之十二栈的应用之栈与递归之阶乘实现
- 9、数据结构笔记之九栈的应用之行编辑实现
- 8、数据结构笔记之八栈的应用之括号匹配检验实现
- Android应用中使用GridView实现数据网格显示(传智播客视频笔记)
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java)
- 数据结构之栈的应用(迷宫问题)
- 数据结构与算法学习笔记——链表部分实现(数组形式)
- 数据结构基础(10) --单链表迭代器的设计与实现
- 数据结构基础(10) --单链表迭代器的设计与实现
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java)
- 数据结构之迷宫求解 使用栈