C++迷宫寻路,利用顺序队,在迷宫中寻找一条从起点到终点的路。

C++迷宫寻路,利用顺序队,在迷宫中寻找一条从起点到终点的路。

因为用到队列解决问题,如果考虑到这个,必须要掌握队列的知识。所以关于队列的代码不多讲解。

迷宫寻路,算法的简单描述:
首先将起点保存到路类型的数组中,pre赋值负一,弹出起点路(因为不是环形队列,出队后仍在队列中(如果不明白可参考环形队列和顺序队的结构)),从起点开始上左下右的寻找路,找到可走的路之后保存到路类型的数组中,弹出最初找到的第一个路(非起点),然后寻找这个弹出的路的上左下右可走的路,然后保存到路类型的数组中,如此循环…如果这个弹出的路是终点,则触发if,输出我们的路径,至于输出要用我们自己改写的print函数,详细看print函数的功能。如果队列为空,则是未找到路径,结束函数,输出未找到路径的提示语。

队列函数
如果记不起他们的作用,可在总代码中查看他们的详细。

void InitQueue(QuType*& q);//初始化队列

bool QueueEmpty(QuType* q);//判断队列是否为空

bool enQueue(QuType*& q, Box e);//加入队列

bool deQueue(QuType*& q, Box& e);//离开队列

void DestroyQueue(QuType*& q);//销毁队列

print函数(我们自己改写的)
作用为输出队列中符合条件的方块(路)

void print(QuType* qu, int front)//我们自己重写的print函数
{                                //作用是输出qu里的路径
	int k = front, j, ns = 0;
	cout << endl;//换行
	do//do-while
	{
		j = k;//do-while先赋值一次再循环
		k = qu->data[k].pre;//赋值给k当前方块的前一个方块的下标
		qu->data[j].pre = -1;//将当前方块的pre设为-1
	} while (k != 0);//pre在输出的时候可作为标记,在寻路的时候是当前方块的上一个方块的下标
	cout << "一条迷宫路径如下:" << endl;
	k = 0;
	while (k <= front)//当k小于front时(可以考虑下为什么)
	{
		if (qu->data[k].pre == -1)//输出所有pre=-1的方块坐标
		{
			ns++;//为排版而存在的变量
			cout << "(";
			cout << qu->data[k].i;
			cout << ",";
			cout << qu->data[k].j;
			cout << ")";//输出坐标
			if (ns % 5 == 0)//五个一行
				cout << endl;
		}
		k++;
	}
	cout << endl;//换行
}

mgpath1函数,本次的寻路函数

bool mgpath1(int xi, int yi, int xe, int ye)//xiyi为出发点的xy,xeye为终点的xy
{
	Box e;//Box类型的e
	int i, j, di, i1, j1;
	QuType* qu;//队列指针
	InitQueue(qu);//初始化
	e.i = xi; e.j = yi; e.pre = -1;//赋值出发点
	enQueue(qu, e);//盒子进队
	mg[xi][yi] = -1;//出发点赋值-1
	while (!QueueEmpty(qu))//当队列不空时循环
	{
		deQueue(qu, e);//出队e,因为不是环形队列,出队后e仍在队列中。
		i = e.i; j = e.j;//赋值e的位置
		if (i == xe && j == ye)//如果e的位置是终点
		{
			print(qu, qu->front);//调用print函数(我们自己重写的函数)
			DestroyQueue(qu);//销毁队列
			return true;//返回真
		}
		for (di = 0; di < 4; di++)//四个方位循环扫描
		{
			switch (di)//di的值决定了选项
			{
			case 0:i1 = i - 1; j1 = j; break;//向左(以图形的角度描述)
			case 1:i1 = i; j1 = j + 1; break;//向下(出发点为左上角)
			case 2:i1 = i + 1; j1 = j; break;//向右
			case 3:i1 = i; j1 = j - 1; break;//向上
			}
			if (mg[i1][j1] == 0)//如果这个点为0(路)
			{
				e.i = i1; e.j = j1;//可走的话将这个添加到e中
				e.pre = qu->front; //e的pre指向上一个方块的下标
				enQueue(qu, e);//进队
				mg[i1][j1] = -1;//赋值该方块为-1表示不可再走
			}
		}
	}
	DestroyQueue(qu);//销毁队列
	return false;//返回假,表示没有找到路径
}

放一下我们的迷宫变量

int mg[M + 2][N + 2] = {//迷宫 1是墙壁 0是路  +2是因为有一圈墙壁
	{1,1,1,1,1,1,1,1,1,1},
	{1,0,0,1,0,0,0,1,0,1},
	{1,0,0,1,0,0,0,1,0,1},
	{1,0,0,0,0,1,1,0,0,1},
	{1,0,1,1,1,0,0,0,0,1},
	{1,0,0,0,1,0,0,0,0,1},
	{1,0,1,0,0,0,1,0,0,1},
	{1,0,1,1,1,0,1,1,0,1},
	{1,1,0,0,0,0,0,0,0,1},
	{1,1,1,1,1,1,1,1,1,1}
};

最后放一下我们很简单的主函数

int main() {
	if (!mgpath1(1, 1, M, N))//调用mgpath1函数,为真则无解
		cout << "该迷宫问题没有解!" << endl;
	return 1;
}

总代码:

#include <iostream>
using namespace std;

const int MaxSize = 100;//足够大,最小等于路的个数(如果不明白可等明白该算法原理再回头看看)
const int M = 8;//迷宫大小(左右长)
const int N = 8;//迷宫大小(上下长)

typedef struct
{
	int i, j;//方块的位置
	int pre;//本路径中上一个方块在队列中的下标
}Box;//方块数据类型

typedef struct
{
	Box data[MaxSize];//方块类型的数组
	int front, rear;//队头指针和队尾指针
}QuType;//顺序队类型

void InitQueue(QuType*& q);//初始化队列

bool QueueEmpty(QuType* q);//判断队列是否为空

bool enQueue(QuType*& q, Box e);//加入队列

bool deQueue(QuType*& q, Box& e);//离开队列

void DestroyQueue(QuType*& q);//销毁队列

void print(QuType* qu, int front);//打印队列

int mg[M + 2][N + 2] = {//迷宫 1是墙壁 0是路  +2是因为有一圈墙壁
	{1,1,1,1,1,1,1,1,1,1},
	{1,0,0,1,0,0,0,1,0,1},
	{1,0,0,1,0,0,0,1,0,1},
	{1,0,0,0,0,1,1,0,0,1},
	{1,0,1,1,1,0,0,0,0,1},
	{1,0,0,0,1,0,0,0,0,1},
	{1,0,1,0,0,0,1,0,0,1},
	{1,0,1,1,1,0,1,1,0,1},
	{1,1,0,0,0,0,0,0,0,1},
	{1,1,1,1,1,1,1,1,1,1}
};

bool mgpath1(int xi, int yi, int xe, int ye)//xiyi为出发点的xy,xeye为终点的xy
{
	Box e;//Box类型的e
	int i, j, di, i1, j1;
	QuType* qu;//队列指针
	InitQueue(qu);//初始化
	e.i = xi; e.j = yi; e.pre = -1;//赋值出发点
	enQueue(qu, e);//盒子进队
	mg[xi][yi] = -1;//出发点赋值-1
	while (!QueueEmpty(qu))//当队列不空时循环
	{
		deQueue(qu, e);//出队e,因为不是环形队列,出队后e仍在队列中。
		i = e.i; j = e.j;//赋值e的位置
		if (i == xe && j == ye)//如果e的位置是终点
		{
			print(qu, qu->front);//调用print函数(我们自己重写的函数)
			DestroyQueue(qu);//销毁队列
			return true;//返回真
		}
		for (di = 0; di < 4; di++)//四个方位循环扫描
		{
			switch (di)//di的值决定了选项
			{
			case 0:i1 = i - 1; j1 = j; break;//向左(以图形的角度描述)
			case 1:i1 = i; j1 = j + 1; break;//向下(出发点为左上角)
			case 2:i1 = i + 1; j1 = j; break;//向右
			case 3:i1 = i; j1 = j - 1; break;//向上
			}
			if (mg[i1][j1] == 0)//如果这个点为0(路)
			{
				e.i = i1; e.j = j1;//可走的话将这个添加到e中
				e.pre = qu->front; //e的pre指向上一个方块的下标
				enQueue(qu, e);//进队
				mg[i1][j1] = -1;//赋值该方块为-1表示不可再走
			}
		}
	}
	DestroyQueue(qu);//销毁队列
	return false;//返回假,表示没有找到路径
}

void print(QuType* qu, int front)//我们自己重写的print函数
{                                //作用是输出qu里的路径
	int k = front, j, ns = 0;
	cout << endl;//换行
	do//do-while
	{
		j = k;//do-while先赋值一次再循环
		k = qu->data[k].pre;//赋值给k当前方块的前一个方块的下标
		qu->data[j].pre = -1;//将当前方块的pre设为-1
	} while (k != 0);//pre在输出的时候可作为标记,在寻路的时候是当前方块的上一个方块的下标
	cout << "一条迷宫路径如下:" << endl;
	k = 0;
	while (k <= front)//当k小于front时(可以考虑下为什么)
	{
		if (qu->data[k].pre == -1)//输出所有pre=-1的方块坐标
		{
			ns++;//为排版而存在的变量
			cout << "(";
			cout << qu->data[k].i;
			cout << ",";
			cout << qu->data[k].j;
			cout << ")";//输出坐标
			if (ns % 5 == 0)//五个一行
				cout << endl;
		}
		k++;
	}
	cout << endl;//换行
}

int main() {
	if (!mgpath1(1, 1, M, N))//调用mgpath1函数,为真则无解
		cout << "该迷宫问题没有解!" << endl;
	return 1;
}


void InitQueue(QuType*& q)//初始化队列
{
	q = (QuType*)malloc(sizeof(QuType));
	q->front = q->rear = -1;
}

bool QueueEmpty(QuType* q)//队列是否为空
{
	return(q->front == q->rear);
}

bool enQueue(QuType*& q, Box e)//进队
{
	if (q->rear == MaxSize - 1)
		return false;
	q->rear++;
	q->data[q->rear] = e;
	return true;
}

bool deQueue(QuType*& q, Box& e)//出队
{
	if (q->front == q->rear)
		return false;
	q->front++;
	e = q->data[q->front];
	return true;
}

void DestroyQueue(QuType*& q)//销毁队列
{
	free(q);
}

遗留问题:没有寻找迷宫中所有可行的路径,没有考虑路径是否最短。功能仅为寻找一条路线。

结构数据教程(第五版)-清华大学出版社
https://blog.csdn.net/sxhelijian/article/details/48465491 数据结构例程——迷宫问题(用队列)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值