数据结构-迷宫寻路系统的设计
简介
这是一个迷宫寻路系统,它的功能是
- 创建迷宫
- 判断迷宫是否有出口
- 输出走出迷宫最少的步数
- 输出走出迷宫的轨迹
在该课题中,我们主要使用了BFS(广度优先搜索)和队列的概念,队列我们使用的是链队列,
下面我先简单介绍一下该队列的结构
c
typedef struct QNode//创建队列节点元素
{
QElemType date;//坐标
struct QNode *next;
}QNode ,*queue;
typedef struct//创建双端队列类型
{
queue front;//队头指针
queue rear;//队尾指针
}Linkqueue;
front为队头,rear为队尾,date域储存坐标信息,而next指针域储存队头和队尾元素的下一个元素地址
在这里我们对链式队列进行了初始化,让队头和队尾元素为new QNode,指针指空
c
int Init(Linkqueue &q)//对链队列进行初始化
{
q.front=q.rear=new QNode;
q.front->next=NULL;
return OK;
}
创建队列和初始化
下面是创建队列的一系列基本操作,增删,获取对头元素
c
int push(Linkqueue &q,QElemType t)
{//向队列中添加元素
queue p;
p=new QNode;
p->date=t;
p->next=NULL;
q.rear->next=p;
q.rear=p;
return OK;
}
int pop(Linkqueue &q,QElemType &t)
{//向队列中删除元素
if(q.front==q.rear) return ERROR;
queue p=q.front->next;
t=p->date;
q.front->next=p->next;
if(q.rear==p) q.rear=q.front;
delete p;
return OK;
}
QElemType Get(Linkqueue q)
{//get方法取对头元素
if(q.front!=q.rear)
return q.front->next->date;
}
做完了这些工作,我们就可以创建迷宫了,我们定义g数组储存迷宫,d数组储存距离,这是创建迷宫的函数
c
void Createmigong(int x,int y)//输入地图
{
for (int i = 0; i < x; i++)
for (int j = 0; j < y; j++)
cin >> g[i][j];
}
用bfs实现的三种方法
剩下是用bfs实现的三个方法,他们大致相同,但是在某些细节又不太一样
memset函数将d数组初始化为-1,判断是否已经走过该路径
c
void Judge_key(int nx,int my)
{//bfs求得是否可以走出迷宫
Linkqueue q;
Init(q);//定义一个队列
QElemType t0;
t0.x=0;
t0.y=0;
int tmp1=push(q,t0);//队尾插入起点(0,0)
memset(d, -1, sizeof(d));//将d[][]初始化为-1,代表没走过
d[0][0]=0;//起点(0,0)已走
int dx[4] ={0,0,-1,1},dy[4] = {1,-1,0,0};//设置偏移量
while(q.front!=q.rear)//队列不为空
{
QElemType t;
t=Get(q);//取队头元素
int t1,t2;
QElemType t3;
int tmp2=pop(q,t3);//出队
for(int i=0;i<4;i++)
{
int x1=t.x+dx[i],y1=t.y+dy[i];//队头元素移动后的坐标
if(x1>=0&&x1<nx&&y1>=0&&y1<my&&g[x1][y1]==0&&d[x1][y1]==-1)//在边界内 并且是0可以走 且之前没有走过
{
d[x1][y1]=d[t.x][t.y]+1;//当前点到起点的距离
QElemType t4;
t4.x=x1;
t4.y=y1;
int tmp3=push(q,t4);
}
}
}
if(d[nx-1][my-1]==-1){
//出口到入口的距离为-1,那么表示没有通路,
cout<<"该迷宫不存在通路"<<endl;
}
else{
cout<<"该迷宫存在通路,请找到走出迷宫的最佳路线"<<endl;
}
}
int bfs(int nx,int my)
{//bfs求得走出迷宫最小步数
Linkqueue q;
Init(q);//定义一个队列
QElemType t0;
t0.x=0;
t0.y=0;
int tmp1=push(q,t0);//队尾插入起点(0,0)
memset(d, -1, sizeof(d));//将d[][]初始化为-1,代表没走过
d[0][0]=0;//起点(0,0)已走
int dx[4] ={0,0,-1,1},dy[4] = {1,-1,0,0};//设置偏移量
while(q.front!=q.rear)//队列不为空
{
QElemType t;
t=Get(q);//取队头元素
int t1,t2;
QElemType t3;
int tmp2=pop(q,t3);//出队
for(int i=0;i<4;i++)
{
int x1=t.x+dx[i],y1=t.y+dy[i];//队头元素移动后的坐标
if(x1>=0&&x1<nx&&y1>=0&&y1<my&&g[x1][y1]==0&&d[x1][y1]==-1)//在边界内 并且是0可以走 且之前没有走过
{
d[x1][y1]=d[t.x][t.y]+1;//当前点到起点的距离
QElemType t4;
t4.x=x1;
t4.y=y1;
int tmp3=push(q,t4);
}
}
}
return d[nx-1][my-1];//返回点(n,m)的距离
}
void bfs1(int nx,int my)
{//bfs1求得走出迷宫轨迹
Linkqueue q;
Init(q);//定义一个队列
QElemType t0;
t0.x=0;
t0.y=0;
int tmp1=push(q,t0);//队尾插入起点(0,0)
memset(d, -1, sizeof(d));//将d[][]初始化为-1,代表没走过
d[0][0]=0;//起点(0,0)已走
int dx[4] ={0,0,-1,1},dy[4] = {1,-1,0,0};//设置偏移量
while(q.front!=q.rear)//队列不为空
{
QElemType t;
t=Get(q);//取队头元素
int t1,t2;
QElemType t3;
int tmp2=pop(q,t3);//出队
for(int i=0;i<4;i++)
{
int x1=t.x+dx[i],y1=t.y+dy[i];//队头元素移动后的坐标
if(x1>=0&&x1<nx&&y1>=0&&y1<my&&g[x1][y1]==0&&d[x1][y1]==-1)//在边界内 并且是0可以走 且之前没有走过
{
d[x1][y1]=d[t.x][t.y]+1;//当前点到起点的距离
prev1[x1][y1]=t;
QElemType t4;
t4.x=x1;
t4.y=y1;
int tmp3=push(q,t4);//把这个没有走过的路径
}
}
}
int x=nx-1,y=my-1;
while(x||y)//有一个不d等于0
{
cout<<"("<<x+1<<" "<<y+1<<")"<<"->";
QElemType t=prev1[x][y];
x=t.x,y=t.y;
}
cout<<"end"<<endl;
}
下面我们通过一张图来描绘一下该迷宫使用bfs的求解流程
其中,关键的是这样一段代码,以此用bfs来寻找它的其他路径
c
int dx[4] ={0,0,-1,1},dy[4] = {1,-1,0,0};//设置偏移量
for(int i=0;i<4;i++)
这里设置了两个数组进行四个方向的遍历,后来循环尽心遍历
以下是该项目源码
项目源码
c
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <cstring>//使用memset函数
#define MAXSIZE 100
#define OK 1
#define ERROR -1
using namespace std;
const int N = 110;
int nx,my;//迷宫的行数和列数 全局变量
int g[N][N];//存储地图 全局变量
int d[N][N];//存储距离 全局变量
pair<int,int> prev2[N];
struct QElemType//存储坐标
{
int x;
int y;
};
QElemType prev1[N][N];//prve1储存路径 全局变量
typedef struct QNode//创建队列节点元素
{
QElemType date;//坐标
struct QNode *next;
}QNode ,*queue;
typedef struct//创建双端队列类型
{
queue front;//队头指针
queue rear;//队尾指针
}Linkqueue;
int Init(Linkqueue &q)//对链队列进行初始化
{
q.front=q.rear=new QNode;
q.front->next=NULL;
return OK;
}
int push(Linkqueue &q,QElemType t)
{//向队列中添加元素
queue p;
p=new QNode;
p->date=t;
p->next=NULL;
q.rear->next=p;
q.rear=p;
return OK;
}
int pop(Linkqueue &q,QElemType &t)
{//向队列中删除元素
if(q.front==q.rear) return ERROR;
queue p=q.front->next;
t=p->date;
q.front->next=p->next;
if(q.rear==p) q.rear=q.front;
delete p;
return OK;
}
QElemType Get(Linkqueue q)
{//get方法取对头元素
if(q.front!=q.rear)
return q.front->next->date;
}
void Createmigong(int x,int y)//输入地图
{
for (int i = 0; i < x; i++)
for (int j = 0; j < y; j++)
cin >> g[i][j];
}
void Judge_key(int nx,int my)
{//bfs求得是否可以走出迷宫
Linkqueue q;
Init(q);//定义一个队列
QElemType t0;
t0.x=0;
t0.y=0;
int tmp1=push(q,t0);//队尾插入起点(0,0)
memset(d, -1, sizeof(d));//将d[][]初始化为-1,代表没走过
d[0][0]=0;//起点(0,0)已走
int dx[4] ={0,0,-1,1},dy[4] = {1,-1,0,0};//设置偏移量
while(q.front!=q.rear)//队列不为空
{
QElemType t;
t=Get(q);//取队头元素
int t1,t2;
QElemType t3;
int tmp2=pop(q,t3);//出队
for(int i=0;i<4;i++)
{
int x1=t.x+dx[i],y1=t.y+dy[i];//队头元素移动后的坐标
if(x1>=0&&x1<nx&&y1>=0&&y1<my&&g[x1][y1]==0&&d[x1][y1]==-1)//在边界内 并且是0可以走 且之前没有走过
{
d[x1][y1]=d[t.x][t.y]+1;//当前点到起点的距离
QElemType t4;
t4.x=x1;
t4.y=y1;
int tmp3=push(q,t4);
}
}
}
if(d[nx-1][my-1]==-1){
//出口到入口的距离为-1,那么表示没有通路,
cout<<"该迷宫不存在通路"<<endl;
}
else{
cout<<"该迷宫存在通路,请找到走出迷宫的最佳路线"<<endl;
}
}
int bfs(int nx,int my)
{//bfs求得走出迷宫最小步数
Linkqueue q;
Init(q);//定义一个队列
QElemType t0;
t0.x=0;
t0.y=0;
int tmp1=push(q,t0);//队尾插入起点(0,0)
memset(d, -1, sizeof(d));//将d[][]初始化为-1,代表没走过
d[0][0]=0;//起点(0,0)已走
int dx[4] ={0,0,-1,1},dy[4] = {1,-1,0,0};//设置偏移量
while(q.front!=q.rear)//队列不为空
{
QElemType t;
t=Get(q);//取队头元素
int t1,t2;
QElemType t3;
int tmp2=pop(q,t3);//出队
for(int i=0;i<4;i++)
{
int x1=t.x+dx[i],y1=t.y+dy[i];//队头元素移动后的坐标
if(x1>=0&&x1<nx&&y1>=0&&y1<my&&g[x1][y1]==0&&d[x1][y1]==-1)//在边界内 并且是0可以走 且之前没有走过
{
d[x1][y1]=d[t.x][t.y]+1;//当前点到起点的距离
QElemType t4;
t4.x=x1;
t4.y=y1;
int tmp3=push(q,t4);
}
}
}
return d[nx-1][my-1];//返回点(n,m)的距离
}
void bfs1(int nx,int my)
{//bfs1求得走出迷宫轨迹
Linkqueue q;
Init(q);//定义一个队列
QElemType t0;
t0.x=0;
t0.y=0;
int tmp1=push(q,t0);//队尾插入起点(0,0)
memset(d, -1, sizeof(d));//将d[][]初始化为-1,代表没走过
d[0][0]=0;//起点(0,0)已走
int dx[4] ={0,0,-1,1},dy[4] = {1,-1,0,0};//设置偏移量
while(q.front!=q.rear)//队列不为空
{
QElemType t;
t=Get(q);//取队头元素
int t1,t2;
QElemType t3;
int tmp2=pop(q,t3);//出队
for(int i=0;i<4;i++)
{
int x1=t.x+dx[i],y1=t.y+dy[i];//队头元素移动后的坐标
if(x1>=0&&x1<nx&&y1>=0&&y1<my&&g[x1][y1]==0&&d[x1][y1]==-1)//在边界内 并且是0可以走 且之前没有走过
{
d[x1][y1]=d[t.x][t.y]+1;//当前点到起点的距离
prev1[x1][y1]=t;
QElemType t4;
t4.x=x1;
t4.y=y1;
int tmp3=push(q,t4);//把这个没有走过的路径
}
}
}
int x=nx-1,y=my-1;
int cnt=1;
while(x||y)//有一个不d等于0
{
prev2[cnt++]={x+1,y+1};
QElemType t=prev1[x][y];
x=t.x,y=t.y;
}
prev2[cnt]={1,1};
for(int i=cnt;i>=0;i--){
cout<<"("<<prev2[i].first<<" "<<prev2[i].second<<")"<<"->";
}
cout<<"end"<<endl;
}
int main()
{
int p=1;
while(p)
{
printf(" 欢迎使用谜宫系统 \n");
printf("------------------------------\n");
printf("1 创建迷宫 \n");
printf("2 判断迷宫是否有出口 \n");
printf("3 输出走出迷宫最少的步数 \n");
printf("4 输出走出迷宫的轨迹 \n");
printf("5 退出 \n");
printf("请输入:\n");
int n;
cin>>n;
if(n==1)
{
printf("0代表可以走,1代表不可以走\n请输入迷宫的行数和列数\n");
cin>>nx>>my;
printf("\n请输入迷宫\n");
Createmigong(nx,my);
}
else if(n==2)
{
Judge_key(nx,my);
}
else if(n==3)
{
printf("走出迷宫最少的步数:%d\n", bfs(nx,my));
}
else if(n==4)
{
printf("出迷宫的轨迹\n");
bfs1(nx,my);
}
else if(n==5)
{
p=0;
cout<<"程序安全退出"<<endl;
}
else
{
printf("非法输入,请重新输入\n");
}
}
return 0;
}