迷宫问题,可以用队列找到所有路径么?c/c++描述

  本号最近总结过关于迷宫问题的多种解法,栈啊,递归啊,队列啊。深度优先啊,广度优先啊,最短路径和所有路径。我们知道用栈的方法是可以找到迷宫里从入口到出口的所有路径,用队列可以找到最短路径。那么用队列是否也能找到所有路径呢?
  答案是可以的。以前我认为不可以,因为对比栈的查找所有路径,找到一条路径后,要进行退栈,回溯,同时把退栈的空格(迷宫由墙壁和空格组成,空格表示可以走的路径)改为可用,以便别的路径能继续使用这些空格。同时考察路径中的空格是否有剩余的方向也是空格,是否可以加入栈,组成新路径。那么在队列里,我们无法进行类似的回溯。队列数组成员里,我们是保存了每个空格的行列坐标和它前面空格的数组下标,但在队列里,假如进行类似的回溯,那么回溯到哪个下标为止,如何更改空格已走过的标记,如何考察其是否有新的可用方向,新路径里的可用空格入队列后,如何与它前面的空格联系起来?考虑这些因素后,以前我认为队列是广度优先搜索,以找到的第一个路径为最短路径。无法找到所有路径。现在在学习二叉树的层序遍历里,又用到了队列,结合对比分析后,感觉可以用队列输出迷宫的所有路径。
  解决方案是,我们要弄清楚,形成迷宫路径的依据是什么:
  ①遇到墙壁不能入路径,遇到空格可以入路径;
  ②若遇到的空格是路径里已经走过的,也不能入路径,要不就形成死循环了。意思是说只能入队列路径里没走过的新方格。
  如此路径必然能越来越远离起点,最终必然能通过各个可能的方向经过终点,形成所有路径。
  在队列里我们不进行回溯,不像栈那样进行退栈回溯。顺序队列里头下标和尾下标都是一往无前,不后退。尾插入新空格,头下标删除空格,头下标越过空格后,就无法再访问它了,相当于从队列里删除了访问过的方格。
  队列头下标访问队列里每个数组元素,若是终点(比较其行列坐标),则表明找到了一条路径,把路径里所有空格用字符’/‘表示,以在屏幕上显示出这条路径,输出后接着头下标加1,继续核对队列数组里下一元素。(注:队列里保存的都不是墙壁,无论是空格还是被别的路径标记过的’/’,都是可以被本当前路径使用的,只要俩路径不完全重合,就是新路径)。若头下标所指并非终点,就要考察其上下左右是否有相邻的合适的方格(既包括空格,也包括’/’,非墙壁就行),合适就是要求方格不能是路径里已有的。只此一条限定就可以。若新方格合适,则入队列,插在尾下标位置。然后头下标加1,继续核对队列里剩余的所有方格。直到遇到尾下标为止。
  如此以来,整个队列里确实能保存多条路径。头下标查找的过程,就是多条路径同时前进的过程,找到一条路径也不要退出程序。让头下标等于尾下标为止,就必然能遍历到队列里的所有路径。终点方格在队列里出现几次,就是对应几条路径。
  因为对于每条路径,要输出其完整路径。所以我们要保存路径里从起点到终点的每一步。所以,我们不能采用循环队列,意思是队列数组的元素数据不能被破坏,直到头下标遇到尾下标为止。队列建的大一点就可以了。
  每一个新方格入队列都要进行核对,程序的时间复杂度会比较大,但电脑嘛,运算速度贼快,现在不让它表现下贼快的运算速度,还等什么时候呢?反正路径找到就可以了,目标完成了。各位若有更好的方法,欢迎指正,一起学习。
完整代码如下:

#include<iostream>
using namespace std;
#define MAXSIZE 100
struct Step {
	int row;
	int column;
	int indexFront;
};
struct Queue {
	Step step[MAXSIZE];
	int indexHead = 0;
	int indexTail = 0;
};/*
char maze[10][10] = {
	'H','H','H','H','H','H','H','H','H','H',
	'H',' ',' ',' ',' ',' ',' ','H',' ','H',
	'H',' ','H','H','H','H',' ',' ',' ','H',
	'H',' ','H',' ',' ','H','H',' ','H','H',
	'H',' ','H','H',' ',' ',' ',' ',' ','H',
	'H',' ',' ',' ','H','H',' ','H',' ','H',
	'H',' ','H',' ',' ',' ','H',' ',' ','H',
	'H',' ',' ','H','H',' ','H','H',' ','H',
	'H','H',' ',' ',' ',' ',' ',' ',' ','H',
	'H','H','H','H','H','H','H','H','H','H'
};*/

char maze[10][10] = {
	'H','H','H','H','H','H','H','H','H','H',
	'H',' ',' ',' ',' ',' ',' ',' ',' ','H',
	'H',' ','H','H','H','H','H','H',' ','H',
	'H',' ','H',' ',' ',' ',' ',' ',' ','H',
	'H',' ','H',' ','H','H','H','H','H','H',
	'H',' ','H',' ','H',' ',' ',' ',' ','H',
	'H',' ','H',' ',' ',' ','H','H',' ','H',
	'H',' ','H','H','H','H','H','H',' ','H',
	'H',' ',' ',' ',' ',' ',' ',' ',' ','H',
	'H','H','H','H','H','H','H','H','H','H'
};

void printAllPath() {
	maze[1][1] = 'I';
	maze[8][8] = 'O';
	for (int row = 0; row <= 9; row++) {
		for (int column = 0; column <= 9; column++)
			cout << maze[row][column];
		cout << endl;
	}
}
void findAllPath(int inRow, int inColumn, int outRow, int outColumn) {
	Queue queue;
	queue.step[0].row = inRow;
	queue.step[0].column = inColumn; //队列初始化,存入起始点
	queue.step[0].indexFront = -1;

	Step stepNext, stepHead;
	bool checkNextStep;//查看下一个要入队列的点是否可以入队列。若为墙壁H或者为
	//当前路径里已经有的点,则为false,不可以入队。否则可以入队列
	while (queue.indexHead <= queue.indexTail) {
		stepHead = queue.step[queue.indexHead];
		//find the exit pot
		if (stepHead.row == outRow && stepHead.column == outColumn) 
			for (int i = stepHead.indexFront;i > 0;) {
				maze[queue.step[i].row][queue.step[i].column] = '/';
				i = queue.step[i].indexFront;
			}
		else //若indexHead指向终点,直接indexHead++,查找队列里下一个点
		//否则表明indexHead指向的点为路径中间的点,应考察下一个合适的点的坐标
			for (int direction = 0; direction <= 3; direction++) {
				checkNextStep = true;//对于每个待检测方格都要先假设可以入队
				switch (direction) {
				case 0://right
					stepNext.row = stepHead.row;
					stepNext.column = stepHead.column + 1; break;
				case 1://down
					stepNext.row = stepHead.row + 1;
					stepNext.column = stepHead.column; break;
				case 2://left
					stepNext.row = stepHead.row;
					stepNext.column = stepHead.column - 1; break;
				case 3://up
					stepNext.row = stepHead.row - 1;
					stepNext.column = stepHead.column; break;
				}

				if (maze[stepNext.row][stepNext.column] != 'H') {
					//查看stepNext将要进入的路径中是否有与stepNext重合的点
					//否则会使路径陷入死循环
					for (int i = stepHead.indexFront; i >= 0;) {
						if (queue.step[i].row == stepNext.row &&
							queue.step[i].column == stepNext.column) {
							checkNextStep = false;
							break;
						}

						i = queue.step[i].indexFront;
					}

					if (checkNextStep) {
						queue.indexTail++;
						queue.step[queue.indexTail] = stepNext;
						queue.step[queue.indexTail].indexFront = queue.indexHead;
					}
				}
			}
		queue.indexHead++;
	}
}
int main() {
	Step steps[MAXSIZE];
	int inRow = 1, inColumn = 1, outRow = 8, outColumn = 8;
	findAllPath(inRow,inColumn,outRow,outColumn);
	printAllPath();
	return 0;
}

测试的迷宫与测试结果如下:
在这里插入图片描述
在这里插入图片描述






在这里插入图片描述
在这里插入图片描述
谢谢阅读。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值