代码目的:通过栈和队列分别实现迷宫的DFS遍历并输出可到达的全部点和BFS遍历输出走出迷宫的最短路径
在迷宫输入到电脑中,以?表示起点,以0表示可走路径,以#表示墙,既不可以走的路径,以*表示可以到达的路径。
一、利用栈实现迷宫的深度遍历并打印路径
1.首先运用一个for循环找到迷宫的起点,将起点存入栈中。
2.再运用一个while循环,依次寻找栈顶元素的上,右,下,左,是否为可到达路径并且未走过,若满足其中一个方向为可到达路径并且未走过时,就直接将其入栈,进行下一次寻找;若四个方向均不满足以上条件,则将栈顶元素出栈,进行下一次查找。
3.直到栈为空时,将遍历过的地方打印出来。
代码中dir[][]数组表示方向,vis[][]数组用于标记走过的点,maze[][]数组用于存储迷宫。
void DFS(char maze[maxn][maxn], int n, int m, char vis[maxn][maxn]){
/*
深度优先遍历的过程
请在本过程中求出从"?"能到达的点数
并将所有能到达的点用"$"覆盖
*/
int i,j,f=0,i1,j1;
stack *st = InitStack();
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
vis[i][j]=maze[i][j];//复制迷宫
}
}
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
if(vis[i][j]=='?')//寻找起点
{
Push(st,i,j,f);//存储起点的位置
st->size--;//不计入节点的步数
}
}
}
while(EmptyStack(st))//当栈为空时结束
{
if(LegalPosition(vis,st->top->x+dir[0][0],st->top->y+dir[0][1],n,m))//判断该点的右边是否能走
{
st->top=Push(st,st->top->x+dir[0][0],st->top->y+dir[0][1],1);
vis[st->top->x][st->top->y]='$';
}
else if(LegalPosition(vis,st->top->x+dir[1][0],st->top->y+dir[1][1],n,m))//判断该点的下边是否能走
{
st->top=Push(st,st->top->x+dir[1][0],st->top->y+dir[1][1],2);
vis[st->top->x][st->top->y]='$';
}
else if(LegalPosition(vis,st->top->x+dir[2][0],st->top->y+dir[2][1],n,m))//判断该点的左边是否能走
{
st->top=Push(st,st->top->x+dir[2][0],st->top->y+dir[2][1],3);
vis[st->top->x][st->top->y]='$';
}
else if(LegalPosition(vis,st->top->x+dir[3][0],st->top->y+dir[3][1],n,m))//判断该点的上边是否能走
{
st->top=Push(st,st->top->x+dir[3][0],st->top->y+dir[3][1],4);
vis[st->top->x][st->top->y]='$';
}
else
{
st->top=Pop(st);//若都不行,则出栈,并退一步
}
}
for(i1=0;i1<n;i1++)
{
for(j1=0;j1<m;j1++)
{
printf("%c", vis[i1][j1]);//打印走完后的迷宫
}
printf("\n");
}
printf("能走到的点的个数为: %d\n \n",st->size);
memset(vis, 0, sizeof(vis));//清除数组
}
二、利用队列实现迷宫的广度遍历并打印最短路径
1.首先运用一个for循环找到迷宫的起点,并将其存入队列。
2.将队列中的队头元素出队,检测其上、右、下、左是否为可到达路径且未走过。若是,则入队,继续检测;若不是,则不入队,继续检测。直到四个方向均扫描过后,对下一个队头元素进行扫描。直到扫描到了出口或者是队列为空。则打印相应的结果。
3.在打印结果的时候,我运用了类似于树的数据结构,对最后的打印结果进行了回溯。在代码中有体现。
void BFS(char maze[maxn][maxn], int n, int m,char vis[maxn][maxn]){
/*
广度优先遍历的过程
请在本过程中求出从"?"出发走出迷宫的最短路长度
并将最短路径用"*"覆盖
*/
int i,j,ret,i1,j1;
Queue *que = InitQueue();//初始化队列
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
vis[i][j]=maze[i][j];//复制迷宫
}
}
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
if(vis[i][j]=='?')//寻找起点
{
que->back=EnQueue(que,i,j);//起点入队
que->front=que->back;
}
}
}
while(isEmpty(que)&&ret!=2)
{
for(i1=0;i1<4;i1++)
{
ret=LegalPosition1(vis,que->front->x+dir[i1][0],que->front->y+dir[i1][1],n,m);//判断是否为合法得点点
if(ret==2)//找到出口
{
printf("Success!\n");
break;
}
if(ret==1)//点合法
{
que->back=EnQueue(que,que->front->x+dir[i1][0],que->front->y+dir[i1][1]);//入队
vis[que->back->x][que->back->y]='*';//标记走过的点
}
}
if(ret!=2)//还没找到出口
{
que->front=DeQueue(que);
}
}
if(ret!=2)//没找到出口
{
printf("Impossible!!!\n");
}
else//找到了出口
{
while(maze[que->front->x][que->front->y]!='?')//进行回溯寻找路径
{
maze[que->front->x][que->front->y]='*';
que->size++;
que->front=que->front->prev;//回溯到上一个结点的
}
for(i1=0;i1<n;i1++)
{
for(j1=0;j1<m;j1++)
{
printf("%c", maze[i1][j1]);//打印最短路径
}
printf("\n");
}
printf("the shortest load is %d\n",que->size);
}
memset(vis, 0, sizeof(vis));
memset(maze,0,sizeof(maze));
}
三、附上总代码
由于博主的迷宫存在一个文件夹里,故主函数里用了文件流。使用代码的时候需要在主函数里有些修改。
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include<assert.h>
#define maxn 1002
/*
maze数组用于存储迷宫
vis数组用于在遍历的时候标记已经访问过的点
dir数组用于表示上下左右方向
n和m分别表示迷宫的行数和列数
*/
char maze[maxn][maxn];
int vis[maxn][maxn];
int dir[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
int n,m;
int LegalPosition(char maze[maxn][maxn],int x, int y,int n,int m){
/* 判断(x,y)位置是否合法*/
if(x<0||x>n-1||y<0||y>m-1)//是否越界
{
return 0;//位置合法
}
if(maze[x][y]=='#'||maze[x][y]=='$'||maze[x][y]=='?')//是否为墙或覆盖过的点
{
return 0;//位置不合法
}
else
{
return 1;//位置合法
}
}
int LegalPosition1(char maze[maxn][maxn],int x, int y,int n,int m){
/* 判断(x,y)位置是否合法*/
if(x<0||x>n-1||y<0||y>m-1)
{
return 2;//找到出口
}
if(maze[x][y]=='#'||maze[x][y]=='*'||maze[x][y]=='?')//是否为墙或覆盖过的点
{
return 0;//位置不合法
}
else
{
return 1;//位置合法
}
}
typedef struct node{
/* 栈中存储的节点 */
int x; // 行坐标
int y; // 列坐标
int flag; // 当前方向
struct node *next; // 栈中上一个节点的指针
/* 可自由添加需要用的变量 */
}node,*pnode;
typedef struct stack{
/* 栈 */
node *top; // 栈顶指针
int size; // 栈中节点个数
node *buttom;//栈底指针
/* 可自由添加需要用的变量 */
}stack,*pstack;
pstack InitStack(){
/* 初始化栈 */
pstack st;
st=(pstack)malloc(sizeof(stack));
assert(st);//判断申请是否成功
st->top=st->buttom;
st->size=0;
return st;
}
int EmptyStack(pstack st)//判栈空
{
if(st->top==st->buttom||st==NULL)//判断是否为空
{
return 0;
}
else
{
return 1;//不为空,返回真
}
}
pnode Push(pstack st,int x1,int y1,int flag1)//入栈
{
pnode n=(pnode)malloc(sizeof(node));//申请新结点
n->x=x1;
n->y=y1;
n->flag=flag1;//flag 1.2.3.4 分别代表上下左右
n->next=st->top;
st->top=n;
st->size++;
return st->top;//返回入栈后的头结点
}
pnode Pop(pstack st)//出栈
{
pnode n;
if(st->top==st->buttom)//判断是否为空
{
printf("The stack is NULL\n");
return;
}
else
{
n=st->top;
st->top=st->top->next;
free(n);
n=NULL;
return st->top;
}
}
void DFS(char maze[maxn][maxn], int n, int m, char vis[maxn][maxn]){
/*
深度优先遍历的过程
请在本过程中求出从"?"能到达的点数
并将所有能到达的点用"$"覆盖
*/
int i,j,f=0,i1,j1;
stack *st = InitStack();
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
vis[i][j]=maze[i][j];//复制迷宫
}
}
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
if(vis[i][j]=='?')//寻找起点
{
Push(st,i,j,f);//存储起点的位置
st->size--;//不计入节点的步数
}
}
}
while(EmptyStack(st))//当栈为空时结束
{
if(LegalPosition(vis,st->top->x+dir[0][0],st->top->y+dir[0][1],n,m))//判断该点的右边是否能走
{
st->top=Push(st,st->top->x+dir[0][0],st->top->y+dir[0][1],1);
vis[st->top->x][st->top->y]='$';
}
else if(LegalPosition(vis,st->top->x+dir[1][0],st->top->y+dir[1][1],n,m))//判断该点的下边是否能走
{
st->top=Push(st,st->top->x+dir[1][0],st->top->y+dir[1][1],2);
vis[st->top->x][st->top->y]='$';
}
else if(LegalPosition(vis,st->top->x+dir[2][0],st->top->y+dir[2][1],n,m))//判断该点的左边是否能走
{
st->top=Push(st,st->top->x+dir[2][0],st->top->y+dir[2][1],3);
vis[st->top->x][st->top->y]='$';
}
else if(LegalPosition(vis,st->top->x+dir[3][0],st->top->y+dir[3][1],n,m))//判断该点的上边是否能走
{
st->top=Push(st,st->top->x+dir[3][0],st->top->y+dir[3][1],4);
vis[st->top->x][st->top->y]='$';
}
else
{
st->top=Pop(st);//若都不行,则出栈,并退一步
}
}
for(i1=0;i1<n;i1++)
{
for(j1=0;j1<m;j1++)
{
printf("%c", vis[i1][j1]);//打印走完后的迷宫
}
printf("\n");
}
printf("能走到的点的个数为: %d\n \n",st->size);
memset(vis, 0, sizeof(vis));//清除数组
}
typedef struct qnode{
/* 队列中存储的节点 */
int x; // 行坐标
int y; // 列坐标
struct qnode *next; //队列中下一个节点的指针
struct qnode *prev; //先驱结点
/* 可自由添加需要用的变量 */
}QueueNode,*pQueueNode;
typedef struct queue{
/* 队列 */
QueueNode *front; //队首指针
QueueNode *back; //队尾指针
int size; // 队列中节点个数
/* 可自由添加需要用的变量 */
}Queue,*pQueue;
Queue *InitQueue(){
/* 初始化队列 */
Queue* que = (Queue *)malloc(sizeof(Queue));//申请空间
assert(que);//判断是否申请成功
que->back=NULL;
que->front=que->back;
que->size = 0;
return que;
}
int isEmpty(Queue *que){
/* 判断队列是否为空 */
if(que->back==NULL)
{
return 0;//为空
}
else
{
return 1;//不为空
}
}
pQueueNode EnQueue(pQueue que,int x1,int y1)
{
/* 入队 */
pQueueNode n=(pQueueNode)malloc(sizeof(QueueNode));//申请空间
n->x=x1;
n->y=y1;
if(que->back==NULL)//队列为空的情况下进行入队
{
que->back=n;
que->front=n;
n->prev=NULL;
return que->back;
}
else//队列不为空的情况下进行入队
{
que->back->next=n;
n->prev=que->front;
que->back=n;
return que->back;
}
}
pQueueNode DeQueue(Queue *que){
/* 出队 */
if(que->back==que->front)//队列只剩一个结点的情况下
{
que->back=NULL;
que->front=que->back;
return que->front;
}
else//队列还有大于等于二个的结点
{
que->front=que->front->next;
return que->front;
}
}
void BFS(char maze[maxn][maxn], int n, int m,char vis[maxn][maxn]){
/*
广度优先遍历的过程
请在本过程中求出从"?"出发走出迷宫的最短路长度
并将最短路径用"*"覆盖
*/
int i,j,ret,i1,j1;
Queue *que = InitQueue();//初始化队列
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
vis[i][j]=maze[i][j];//复制迷宫
}
}
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
if(vis[i][j]=='?')//寻找起点
{
que->back=EnQueue(que,i,j);//起点入队
que->front=que->back;
}
}
}
while(isEmpty(que)&&ret!=2)
{
for(i1=0;i1<4;i1++)
{
ret=LegalPosition1(vis,que->front->x+dir[i1][0],que->front->y+dir[i1][1],n,m);//判断是否为合法得点点
if(ret==2)//找到出口
{
printf("Success!\n");
break;
}
if(ret==1)//点合法
{
que->back=EnQueue(que,que->front->x+dir[i1][0],que->front->y+dir[i1][1]);//入队
vis[que->back->x][que->back->y]='*';//标记走过的点
}
}
if(ret!=2)//还没找到出口
{
que->front=DeQueue(que);
}
}
if(ret!=2)//没找到出口
{
printf("Impossible!!!\n");
}
else//找到了出口
{
while(maze[que->front->x][que->front->y]!='?')//进行回溯寻找路径
{
maze[que->front->x][que->front->y]='*';
que->size++;
que->front=que->front->prev;//回溯到上一个结点的
}
for(i1=0;i1<n;i1++)
{
for(j1=0;j1<m;j1++)
{
printf("%c", maze[i1][j1]);//打印最短路径
}
printf("\n");
}
printf("the shortest load is %d\n",que->size);
}
memset(vis, 0, sizeof(vis));
memset(maze,0,sizeof(maze));
}
int main()
{
/* 从文件maze.in中读入 */
freopen("maze.in","r",stdin);
int o=0,i,j;
printf("Please input data:\n");
while (scanf("%d %d",&n,&m)!=EOF){
// 可能有多组输入数据
o += 1;
for (i=0;i<n;i++)
for (j=0;j<m;j++)
scanf(" %c", &maze[i][j]);
printf("--------Case #%d--------\n", o);
DFS(maze, n, m,vis);
BFS(maze, n, m,vis);
}
fclose(stdin);
return 0;
}