在地图中找到路径

####前提:####
重新看数据结构,自己总结并加深印象

####问题:####

在二维地图中,0代表此路可以走,1代表是墙,从(1,1)坐标走到(8,8),找出路径(不考虑斜的走)
地图如下:
map[10][10] = {
1,1,1,1,1,1,1,1,1,1,
1,0,1,0,0,0,0,0,0,1,
1,0,1,1,0,0,0,0,1,1,
1,0,0,0,0,0,1,0,0,1,
1,0,0,0,1,0,1,1,0,1,
1,0,0,0,1,0,1,0,0,1,
1,0,1,0,0,0,1,0,0,1,
1,0,1,0,1,0,0,0,0,1,
1,0,0,0,1,0,0,1,0,1,
1,1,1,1,1,1,1,1,1,1};

####1.栈实现###
大致思路:
   1. 设置节点Node,保存一个格子的x,y 和 方向
   2. 从右边顺时针访问相邻的格子,判断相邻格子中是否是墙,如果不是墙则保存要走的方向,把相邻的格子加入栈中
   3. 如果一个格子中4个方向都走过,则栈中要弹出这个格子(也就意味着这个格子已经走到底了),返回上一个格子,再检测相邻格子是否能走
注意:
   在判断完格子a相邻格子中哪个可以走时,要在map中把格子a的位置设为1,为了防止下个格子判断相邻格子时往回判断
总结:
   回溯,要保存每个格子走过的方向
   类似于深度优先搜索,运气好可能是最短路径
伪代码 :

while(栈不为空)
{
	得到栈顶格子a
	if(此格子是终点)
	{
		return true
	}
	找到相邻位置中哪个格子可以走
	if(有格子b可以走)
	{
		地图中格子a的位置设为1
		栈中加入此格子
	}
	else
	{
		地图中格子a的位置设为0
		栈中弹出格子a
	}
}

代码 :

#include <iostream>
#include <stack>

using namespace std;

int map[10][10] =
{
	  /*  1,2,3,4,5,6,7,8,9*/
		1,1,1,1,1,1,1,1,1,1,
/*1*/	1,0,1,0,0,0,0,0,0,1,
/*2*/	1,0,1,1,0,0,0,0,1,1,
/*3*/	1,0,0,0,0,0,1,0,0,1,
/*4*/	1,0,0,0,1,0,1,1,0,1,
/*5*/	1,0,0,0,1,0,1,0,0,1,
/*6*/	1,0,1,0,0,0,1,0,0,1,
/*7*/	1,0,1,0,1,0,0,0,0,1,
/*8*/	1,0,0,0,1,0,0,1,0,1,
/*9*/	1,1,1,1,1,1,1,1,1,1
};

struct Node
{
	int x;
	int y;
	int dir;
};

bool FindSrcByStack(int startX, int startY, int endX, int endY, int(*map)[10], stack<Node> & resultPath)
{
	stack<Node> storePath;
	Node startNode;
	startNode.x = startX;
	startNode.y = startY;
	startNode.dir = -1;
	storePath.push(startNode);

	while (!storePath.empty())
	{
		//拿出栈顶格子
		Node node = storePath.top();
		int x = node.x;
		int y = node.y;
		int dirIndex = node.dir;
		bool isFind = false;
		
		//此格子是终点
		if (x == endX && y == endY)
		{
			while (!storePath.empty())
			{
				Node node = storePath.top();
				resultPath.push(node);
				storePath.pop();
			}
			return true;
		}
		
		//找到相邻位置中哪个格子可以走
		int ii = x;
		int jj = y;
		while (dirIndex < 4 && !isFind)
		{
			dirIndex++;
			switch (dirIndex)
			{
			case 0:
				ii = x;jj = y + 1; break;
			case 1:
				ii = x + 1; jj = y; break;
			case 2:
				ii = x; jj = y - 1; break;
			case 3:
				ii = x + 1; jj = y; break;
			}

			if (map[ii][jj] == 0)
			{
				isFind = true;
				map[ii][jj] = 1;
				break;
			}
		}
		
		//有格子b可以走
		if (isFind)
		{
			//地图中格子a的位置设为1
			//栈中加入此格子
			Node nextNode;
			nextNode.x = ii;
			nextNode.y = jj;
			nextNode.dir = -1;
			storePath.top().dir = dirIndex;
			storePath.push(nextNode);
		}
		else
		{
			//地图中格子a的位置设为0
			//栈中弹出格子a
			storePath.pop();
			map[x][y] = 0;
		}
	}

	return false;
}

void Print(stack<Node> path)
{
	while (!path.empty())
	{
		Node node = path.top();
		cout << "(" << node.x << "," << node.y << ")" << endl;
		path.pop();
	}
}

结果:
这里写图片描述

####2.队列实现####
大致思路:
   1. 设置节点Node,保存 前面格子的位置(即格a 到 格b ,我在格b保存 格a的位置)
   2. 从格子a 右边顺时针访问相邻的格子,判断相邻格子中是否是墙,如果不是墙则保存要走的方向,把四周能走的格子全部加入队列中,并且 保存 格子a 位置
   3. 再从队列中拿出格子,反复格子2操作,有格子是最后终点 或者 队列为空
注意:
   在判断完格子a相邻格子中哪个可以走时,要在map中把格子a的位置设为1,为了防止下个格子判断相邻格子时往回判断
总结:
   需要记录上一个格子的位置,根据这个记录来显示路径
   类似于广度优先搜索,这个路径找出来肯定是最短路径
伪代码 :

while(队列不为空)
{
	从队列前面拿出格子
	if(拿出的格子是终点)
	{
		return true;
	}
	
	while(遍历四周格子)
	{
		if(格子是否不是墙)
		{
			加入队列
			map中设置格子处为1
		}
	}
}

代码 :

#include <iostream>
#include <queue>
#include <vector>

using namespace std;

int map[10][10] =
{
	  /*  1,2,3,4,5,6,7,8,9*/
		1,1,1,1,1,1,1,1,1,1,
/*1*/	1,0,1,0,0,0,0,0,0,1,
/*2*/	1,0,1,1,0,0,0,0,1,1,
/*3*/	1,0,0,0,0,0,1,0,0,1,
/*4*/	1,0,0,0,1,0,1,1,0,1,
/*5*/	1,0,0,0,1,0,1,0,0,1,
/*6*/	1,0,1,0,0,0,1,0,0,1,
/*7*/	1,0,1,0,1,0,0,0,0,1,
/*8*/	1,0,0,0,1,0,0,1,0,1,
/*9*/	1,1,1,1,1,1,1,1,1,1
};

struct QNode
{
	int x;
	int y;
	int preNode;
};

bool FindSrcByQueue(int startX, int startY, int endX, int endY, int(*map)[10], stack<QNode> & resultPath)
{
	queue<QNode> storePath;
	vector<QNode> tmpStoreResultPath;
	QNode startNode;
	startNode.x = startX;
	startNode.y = startY;
	startNode.preNode = -1;

	storePath.push(startNode);

	int preIndex = -1;

	while (!storePath.empty())
	{
		QNode node = storePath.front();
		tmpStoreResultPath.push_back(node);
		storePath.pop();
		preIndex++;
		node.preNode = preIndex;
		int x = node.x;
		int y = node.y;
		int dirIndex = -1;
		int ii = x;
		int jj = y;

		if (x == endX && y == endY)
		{
			QNode resultNode = tmpStoreResultPath.back();
			do
			{
				resultPath.push(resultNode);
				resultNode = tmpStoreResultPath[resultNode.preNode];
			} while (resultNode.preNode != -1);
			resultPath.push(tmpStoreResultPath[0]);
			return true;
		}

		while (dirIndex < 4)
		{	
			dirIndex ++;
			switch (dirIndex)
			{
			case 0:
				ii = x;jj = y + 1;break;
			case 1:
				ii = x + 1;jj = y;break;
			case 2:
				ii = x;jj = y - 1;break;
			case 3:
				ii = x - 1;jj = y;break;
			}

			if (map[ii][jj] == 0)
			{
				QNode newNode;
				newNode.x = ii;
				newNode.y = jj;
				newNode.preNode = preIndex;
				map[ii][jj] = 1;
				storePath.push(newNode);
			}
		}
		
	}

	return false;
}

void Print(stack<QNode> path)
{
	while (!path.empty())
	{
		QNode node = path.top();
		cout << "(" << node.x << "," << node.y << ")" << endl;
		path.pop();
	}
}

结果:
这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值