广度寻路算法思想及代码


我的理解:广度寻路算法是以 一颗树根开始,树 不断蔓延至整个地图所有能到达的位置,当树干上的某一片树叶碰到了终点,则到达终点, 因此广度寻路算法是一个寻找最短路径的过程

关于深度寻路算法,可以看我写的另一篇,点这里!!!!

位置的点类型

存储每个位置的x y坐标,下面描述的点都是以(row,col)描述,即先行再列

//确定点类型
struct Mypoint
{
	int row;
	int col;
	bool operator==(const Mypoint& pos)
	{
        //用于判断某个点是否到达终点
		return (row == pos.row && col == pos.col);
	}
};

树结构存储整条路线

每个节点都要存储每个位置点坐标,并且这个节点具有父节点和孩子节点孩子节点可能有多个,例如: 注意:父节点只有一个,因为每个父节点会单独考虑它所拥有的孩子节点
在这里插入图片描述

  • 用一个容器存储多个孩子节点,每个孩子节点都是TreeNode*类型
//利用树结构存储整条路线
struct TreeNode
{
	Mypoint		pos;			//存储每个位置点
	TreeNode* pParent;			//父节点
	vector<TreeNode*>	pChild;	//每个点周围有四个方向,记录四个位置
};

为寻路做准备

  • 地图,bool类型辅助地图(判断某个位置有没有走过,走过则为true,走过了则之后不能再走)。

  • 规定起始点,终点,试探点(提前试探位置的一个辅助点,帮助看能否移动)。

  • 准备一颗树,起始点作为树根。

  • 利用数组(容器)存储树的每一层的节点,要有存储当前层存储下一层两个数组。

  • 树根首先进入当前层的容器中

int map[ROW][COL] =
	{
		{1,1,1,1,1,1,1,1,1,1},
		{1,0,1,1,0,0,0,0,1,1},
		{1,0,1,1,0,1,1,1,1,1},
		{1,0,1,1,0,1,1,1,1,1},
		{1,0,0,0,0,0,0,0,1,1},
		{1,0,1,0,1,0,1,0,1,1},
		{1,0,1,0,1,0,1,0,1,1},
		{1,0,1,0,1,0,1,0,1,1},
		{1,0,1,0,1,0,0,0,0,1},
		{1,0,0,0,1,1,1,1,1,1},
	};
	//辅助地图存储某一个位置是否已经走过
	bool pathMap[ROW][COL] = { 0 };	//一开始都没走过

	//起始点
	Mypoint	Begpos{ 1,1 };
	Mypoint Endpos{ 8,8 };
	Mypoint searchpos;	//试探点

	//准备一棵树  起点当作根节点
	TreeNode* pRoot = Create_TreeNode(Begpos);	
	TreeNode* pTemp = NULL;

	//利用数组存储树的每一层的节点
	vector<TreeNode*> CurrentRow;	//当前层节点
	vector<TreeNode*> NextRow;		//下一层节点
	
	//起始点存入容器
	CurrentRow.push_back(pRoot);

广度寻路过程

  1. 每一层存储可以移动的节点,从第一层开始依次遍历每个节点
  2. 每个节点都有四个方向,再依次遍历四个方向
    • 试探点设置为当前点坐标
    • 试探点的row col根据方向依次发生变化
    • 判断移动后的试探点的位置是否是能够正确移动的位置,即该点没有越界,不是墙壁,没有走过
    • 如果在此方向可以移动,则创建一个树节点pTemp,pTemp记录者位置的坐标,pTemp成为当前点的孩子,当前点成为pTemp的父亲,pTemp存入下一层。
  3. 当前层移动到下一层,重新开始遍历新的一层,重复执行步骤1
  4. 当有多条路径时,如果有一条最短的路径到达了终点,则循环停止,可以获取这条最短的路径。

注意:

  • CurrentRow.size() 容器成员函数,返回当前层共有多少个节点依次进行操作
  • 对每个节点再进行4个方向的遍历移动
  • 如果某个方向可以移动,则移动到该点,并创建该点的树节点,确定父子关系
  • 每次遍历一层,并存储下一层的节点,如果到达死胡同,则存储下一层节点的容器为空,则退出,我们提前结束到达终点的情况,不依赖此情况
while (1)
	{
		NextRow.clear();	//循环一次之后,刷新存储下一层的数组
		//依次操作每一层的节点
		for (int i = 0; i < CurrentRow.size(); i++)
		{
			//标记当前点走过
			pathMap[CurrentRow[i]->pos.row][CurrentRow[i]->pos.col] = true;
			//对于每个节点都有4个方向
			for (int j = 0; j < NUM; j++)
			{
				//试探点就是当前点位置
				searchpos = CurrentRow[i]->pos;
				switch (j)
				{
				case p_up:searchpos.row--;
					break;
				case p_right:searchpos.col++;
					break;
				case p_down:searchpos.row++;
					break;
				case p_left:searchpos.col--;
					break;
				}
				//某个方向可以移动
				if (IsCanWalk(map,pathMap,searchpos))
				{
					//创建新的树节点
					pTemp = Create_TreeNode(searchpos);
					//入树
					//pTemp称为当前点的孩子
					CurrentRow[i]->pChild.push_back(pTemp);
					//当前点成为pTemp的父亲
					pTemp->pParent = CurrentRow[i];
					//pTemp存入下一层数组中
					NextRow.push_back(pTemp);
					//判断是否是终点
					if (pTemp->pos == Endpos)
					{
						isFindEnd = true;
						goto jmp;
					}
				}
			}
		}
		if (NextRow.size() == 0)
		{
			//地图遍历完了还是没有终点
			break;
		}
		//当前层移动到下一层
		CurrentRow = NextRow;
	}

完整代码

在这里插入图片描述

#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
using namespace std;

#define ROW 10
#define COL 10
//最多四个方向
#define NUM 4	

enum Dir
{
	p_up,
	p_right,
	p_left,
	p_down
};

//确定点类型
struct Mypoint
{
	int row;
	int col;
	bool operator==(const Mypoint& pos)
	{
		return (row == pos.row && col == pos.col);
	}
};

//利用树结构存储整条路线
struct TreeNode
{
	Mypoint		pos;			//存储每个位置点
	TreeNode* pParent;			//父节点
	vector<TreeNode*>	pChild;	//每个点周围有四个方向,记录四个位置
};

//创建树节点
TreeNode* Create_TreeNode(const Mypoint& pos);

//判断四个方向的某个位置能不能走
bool IsCanWalk(int map[ROW][COL], bool pathMap[ROW][COL], Mypoint pos);
int main()
{
	int map[ROW][COL] =
	{
		{1,1,1,1,1,1,1,1,1,1},
		{1,0,1,1,0,0,0,0,1,1},
		{1,0,1,1,0,1,1,1,1,1},
		{1,0,1,1,0,1,1,1,1,1},
		{1,0,0,0,0,0,0,0,1,1},
		{1,0,1,0,1,0,1,0,1,1},
		{1,0,1,0,1,0,1,0,1,1},
		{1,0,1,0,1,0,1,0,1,1},
		{1,0,1,0,1,0,0,0,0,1},
		{1,0,0,0,1,1,1,1,1,1},
	};
	//辅助地图存储某一个位置是否已经走过
	bool pathMap[ROW][COL] = { 0 };	//一开始都没走过

	//起始点
	Mypoint	Begpos{ 1,1 };
	Mypoint Endpos{ 8,8 };
	Mypoint searchpos;	//试探点

	//准备一棵树  起点当作根节点
	TreeNode* pRoot = Create_TreeNode(Begpos);	
	TreeNode* pTemp = NULL;

	//利用数组存储树的每一层的节点
	vector<TreeNode*> CurrentRow;	//当前层节点
	vector<TreeNode*> NextRow;		//下一层节点
	
	//起始点存入容器
	CurrentRow.push_back(pRoot);
	
	bool isFindEnd = false;

	while (1)
	{
		NextRow.clear();
		//依次操作每一层的节点
		for (int i = 0; i < CurrentRow.size(); i++)
		{
			//标记当前点走过
			pathMap[CurrentRow[i]->pos.row][CurrentRow[i]->pos.col] = true;
			//对于每个节点都有4个方向
			for (int j = 0; j < NUM; j++)
			{
				//试探点就是当前点位置
				searchpos = CurrentRow[i]->pos;
				switch (j)
				{
				case p_up:searchpos.row--;
					break;
				case p_right:searchpos.col++;
					break;
				case p_down:searchpos.row++;
					break;
				case p_left:searchpos.col--;
					break;
				}
				//某个方向可以移动
				if (IsCanWalk(map,pathMap,searchpos))
				{
					//创建新的树节点
					pTemp = Create_TreeNode(searchpos);
					//入树
					//pTemp称为当前点的孩子
					CurrentRow[i]->pChild.push_back(pTemp);
					//当前点成为pTemp的父亲
					pTemp->pParent = CurrentRow[i];
					//pTemp存入下一层数组中
					NextRow.push_back(pTemp);
					//判断是否是终点
					if (pTemp->pos == Endpos)
					{
						isFindEnd = true;
						goto jmp;
					}
				}
			}
		}
		if (NextRow.size() == 0)
		{
			//地图遍历完了还是没有终点
			break;
		}
		//当前层移动到下一层
		CurrentRow = NextRow;
	}
jmp:;
	if (isFindEnd)
	{
		cout << "到达终点!\n";
		while (pTemp)
		{
			cout << "(" << pTemp->pos.row << "," << pTemp->pos.col << ")" << " ";
			pTemp = pTemp->pParent;
		}
	}
	system("pause");
	return 0;
}

//创建树节点
TreeNode* Create_TreeNode(const Mypoint& pos)
{
	TreeNode* pNew = new TreeNode;
	if (!pNew)
	{
		cerr << "节点创建失败!\n";
		exit(-1);
	}
	//元素重置为零
	memset(pNew, 0, sizeof(TreeNode));
	pNew->pos = pos;	//把能够移动的点位置存储起来
	return pNew;
}

//判断四个方向的某个位置能不能走
bool IsCanWalk(int map[ROW][COL], bool pathMap[ROW][COL], Mypoint pos)
{
	//首先判断越界
	if (pos.row < 0 || pos.row >= ROW || pos.col < 0 || pos.col >= COL)
	{
		return false;
	}
	//墙壁
	if (map[pos.row][pos.col] == 1)
	{
		return false;
	}
	//走过的不能再走
	if (pathMap[pos.row][pos.col])
	{
 		return false;
	}
	return true;
}
posted @ 2022-08-10 14:00  hugeYlh  阅读(12)  评论(0编辑  收藏  举报  来源