数据结构-迷宫寻路系统的设计
简介
这是一个迷宫寻路系统,它的功能是
- 创建迷宫
- 判断迷宫是否有出口
- 输出走出迷宫最少的步数
- 输出走出迷宫的轨迹
在该课题中,我们主要使用了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;
}