广度优先搜索

图搜索算法---广度优先搜索

广度优先:bfs

一、注意事项

1.走直线,不能走斜线

2.理解为树的层次次序

3.如果有路,必然找到最短路径

4.需要遍历所有可通行的节点,如果地图比较大,开销就比较大

5.如果已经搜索过,就不再搜索

6.同时向所有可通过的的方向进行搜索

思路:其实和深度优先搜索没什么区别,就是在判断的时候,深度始终是一个点一个点的走,而广度会把下一步能走的路都走一遍

资源数组不要改动

二、代码示例

#include<iostream>
using namespace std;

#define MAP_ROW 6
#define MAP_COL 8

//路径点信息
struct MyPoint
{
	int row, col;
};

//寻路的方向
enum PathDir
{
	p_up, p_down, p_left, p_right
};

//辅助数组中元素的类型(结构体)
struct PathNode
{
	int val;//原始数组的原始地图的值
	PathDir dir;//保存这个路径寻路的方向,为数组中每一个元素准备一个方向
	bool isFind;//标记这个路径点是否走过
};

//准备树形结构的节点类型
#include<vector>

struct MyTreeNode
{
	MyPoint pos;//数据域,记录着某个行列坐标,表示一个路径点
	MyTreeNode* parent;//当前节点的父节点
	vector<MyTreeNode*> child;//指向当前节点所有子节点的指针数组
};
//清除树形结构中的所有节点
void clearTree(MyTreeNode*&root)
{
	if (root)
	{
		for (size_t i = 0; i < root->child.size(); i++)
		{
			clearTree(root->child[i]);
		}
		delete root;
		root = nullptr;
	}
}

bool checkPoint(PathNode arr[][MAP_COL], MyPoint p)
{
	if (p.row >= 0 && p.col >= 0 && p.row < MAP_ROW&&p.col < MAP_COL)
	{
		//表示在地图范围之内
		//表示要可通行并且路径点没有被访问
		if (arr[p.row][p.col].val == 0 && !arr[p.row][p.col].isFind)
		{
			return true;
		}
	}
	return false;
}

int main()
{
	//原始地图
	int arr[MAP_ROW][MAP_COL] = {
		{ 0, 0, 0, 0, 0, 0, 0, 0 },
		{ 0, 0, 0, 0, 1, 0, 0, 0 },
		{ 0, 0, 0, 0, 1, 0, 0, 0 },
		{ 0, 0, 0, 0, 1, 0, 0, 0 },
		{ 0, 0, 0, 0, 1, 0, 0, 0 },
		{ 0, 0, 0, 0, 1, 0, 0, 0 }
	};

	//因为原来的地图不能改动,所以要准备一个辅助数组,用来存储原数组的数据,而且还将辅助地图中的元素,加了几个属性,一个是数组中元素的寻路方向,还有标记了当前路径点是否被访问
	//准备辅助地图
	PathNode pathArr[MAP_ROW][MAP_COL];
	for (int i = 0; i < MAP_ROW; i++)
	{
		for (int j = 0; j < MAP_COL; j++)
		{
			pathArr[i][j].val = arr[i][j];//将原地图的坐标保存到辅助地图中
			pathArr[i][j].dir = p_up;//记录寻路方向
			pathArr[i][j].isFind = false;//表示还未走过
		}
	}

	//准备起点和终点
	MyPoint beginPoint = { 2,3 };
	MyPoint endPoint = { 4,6 };
	pathArr[beginPoint.row][beginPoint.col].isFind = true;//将起点标记为已访问
	
	//开始搜索,并保存搜索的数据
	MyTreeNode* pRoot = new MyTreeNode;//分配一个内存给根节点
	pRoot->pos = beginPoint;//根节点里面的路径点就是起点
	pRoot->parent = nullptr;//根节点是没有父节点的
	//根节点到目前为止,子节点是未知的,并不知道child是怎样赋值的

	//因为树形结构表兄弟之间无法直接联系,需要借助两个辅助数组来保存节点的首地址
	//两个辅助数组,一个用来表示父节点层的所有元素的首地址,一个是用来表示子节点层的所有元素的首地址
	//指针数组,每一个元素都是指针
	vector<MyTreeNode*> currentList;//表示当前节点层(子节点层)
	vector<MyTreeNode*> nextList;//表示当前节点层的下一层(子节点层)

	currentList.push_back(pRoot);//表示当前父节点层为根节点,通过这个去搜索根节点的子节点层
	MyPoint tempPoint;//临时变量,用来记录当前位置的下一个位置的行列
	//开始搜索--逻辑代码
	while (true)//不知道怎么退出,就写成死循环
	{
		//循环查找父节点层的所有元素,次数表示当前父节点层有多少个元素
		for (int i = 0; i < (int)currentList.size(); i++)
		{
			//四个方向循环查找
			for (int j = 0; j < 4; j++)
			{
				//在这里初始化的目的是要循环四个方向,让临时变量==父节点层中每一个元素的坐标位置
				tempPoint = currentList[i]->pos;
				switch (j)
				{
				case p_up:
					tempPoint.row--;
					break;
				case p_down:
					tempPoint.row++;
					break;
				case p_left:
					tempPoint.col++;
					break;
				case p_right:
					tempPoint.col--;
					break;
				}
				if (checkPoint(pathArr, tempPoint))
				{
					//表示可通行
					//准备构建树形结构
					MyTreeNode* insertNode = new MyTreeNode;//待插入节点申请内存
					//指向临时变量
					insertNode->pos = tempPoint;

					//树形结构的建立
					//子节点关联上父节点
					insertNode->parent = currentList[i];//currentList[i]是一个指针,指向一个路径点
					//父节点关联上子节点
					currentList[i]->child.push_back(insertNode);
					//标记当前节点已访问
					pathArr[tempPoint.row][tempPoint.col].isFind = true;

					//将当前节点压入子节点层中
					nextList.push_back(insertNode);

					if (insertNode->pos.row == endPoint.row&&insertNode->pos.col == endPoint.col)
					{
						//表示找到了终点
						MyTreeNode* pNode = insertNode;
						while (pNode)
						{
							printf("row=%d,\tcol=%d\n", pNode->pos.row, pNode->pos.col);
							pNode = pNode->parent;
						}
						goto LABED;
					}

				}
			}
		}
		//表示没有找到终点
		if (nextList.size() == 0)
		{
			goto LABED;
		}
		currentList = nextList;//将原来的子节点变为父节点层,在把原来的子节点层中所有的数据删除
		nextList.clear();

	}
LABED:
	clearTree(pRoot);//清除树中数据


	return 0;
}
posted @ 2021-04-09 17:02  kisfly  阅读(157)  评论(0编辑  收藏  举报