广度寻路算法思想及代码


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

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

位置的点类型

存储每个位置的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 @   hugeYlh  阅读(25)  评论(0编辑  收藏  举报  
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示