广度寻路算法的思想
将实际地图抽象为树(四叉树,四个方向)。起点就是树的根节点,是树的第一层。走一步能到达的节点都是根节点的孩子,是树的第二层。走两步能到达的节点是树的第三层…当树的叶子到达终点或没有地方拓展了,寻路结束。
找到终点后一路往上回溯,一直追溯到起点,这条路径就是最佳路径。
树的结构
enum dir{e_up,e_right,e_down,e_left};
typedef struct Point
{
int x, y;
}Point;
typedef struct treeNode
{
Point pt;
struct treeNode* parent;
struct treeNode* arr[4];//孩子数组
int arrSize;//孩子个数
}treeNode;
创建结点
treeNode* creatTree(int row, int col)
{
treeNode* pNew = malloc(sizeof(struct treeNode));
if (NULL == pNew) return NULL;
memset(pNew, 0, sizeof(struct treeNode));
pNew->pt.x = row;
pNew->pt.y = col;
return pNew;
}
寻路准备
-
地图,辅助地图(判断某个位置有没有走过,走过则为true,走过了则之后不能再走)。
-
规定起始点,终点,试探点(帮助看能否移动)。
-
准备一颗树,起始点作为树根。
-
利用数组存储树的当前层结点和下一层结点
-
树根首先进入当前层数组
//地图
int map[ROW][COL] = {
{0,1,0,0,0,0,0,0,0,0},
{0,1,0,1,0,1,0,1,1,1},
{0,1,0,1,0,0,0,0,0,1},
{0,0,0,1,0,1,0,0,0,1},
{0,1,0,0,0,0,0,0,0,1},
{0,1,0,1,0,0,0,0,0,1},
{0,1,0,1,0,1,0,0,0,0},
{0,1,0,1,0,0,0,1,0,1},
{0,1,0,1,0,1,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1}
};
//辅助地图
bool isFind[ROW][COL] = { 0 };
Point begPot = { 0,0 };
Point endPot = { 6,9 };
isFind[begPot.x][begPot.y] = true;
treeNode* root = creatTree(0, 0);
//当前层
treeNode* cur[100] = { root };
int curSize = 1;
//下一层
treeNode* next[100];
int nextSize = 0;
//当前点
treeNode* curNode=NULL;
//试探点
treeNode* temp=NULL;
//是否找到终点
bool isEnd=false;
寻路过程
- 从第一层开始依次遍历每个结点
- 每个节点都有四个方向,再依次遍历四个方向
- 当前点为当前层对应点
- 创建试探结点temp
- 试探点的row col根据方向依次发生变化
- 判断移动后的试探点的位置是否是能够正确移动的位置,即该点没有越界,不是墙壁,没有走过
- 如果在此方向可以移动,temp成为当前点的孩子,当前点成为temp的父亲,temp存入下一层。
- 当前层移动到下一层,重新开始遍历新的一层
- 如果不能,则销毁temp。
- 判断是否找到终点,如果是isEnd=true,跳出循环。
- 每个节点都有四个方向,再依次遍历四个方向
- 重复执行步骤
当有多条路径时,如果有一条最短的路径到达了终点,则循环停止,可以获取这条最短的路径。
while (1)
{
for (int i = 0; i < curSize; i++)
{
for (int j = 0; j < 4; j++)//向四个方向试探
{
curNode = cur[i];
temp = creatTree(curNode->pt.x, curNode->pt.y);
switch (j)
{
case e_up:
temp->pt.x--;
break;
case e_right:
temp->pt.y++;
break;
case e_down:
temp->pt.x++;
break;
case e_left:
temp->pt.y--;
break;
}
//判断能不能走
if(canWalk(temp->pt,map,isFind))
{
//入树
temp->parent = curNode;
curNode->arr[curNode->arrSize++] = temp;
//标记走过
isFind[temp->pt.x][temp->pt.y] = true;
//是当前层的下一层
next[nextSize++] = temp;
//判断是不是终点
if (temp->pt.x == endPot.x && temp->pt.y == endPot.y)
{
isEnd = true;
break;
}
}
else//不能
{
free(temp);
temp = NULL;
}
}//end j
if (isEnd)
break;
}//end i
if (isEnd)
break;
if (nextSize == 0)
break;
//切换到下一层
memcpy(cur, next, sizeof(treeNode*) * nextSize);
curSize = nextSize;
//下一层清空
memset(next, 0, sizeof(treeNode*) * nextSize);
nextSize = 0;
}//end while
if (isEnd)
{
printf("找到终点了\n");
while (temp) {
printf("(%d,%d)",
temp->pt.x,
temp->pt.y);
temp = temp->parent;
}
printf("\n");
}
}
bool canWalk(Point pt, int map[ROW][COL], bool isFind[ROW][COL])
{
//越界
if (pt.x >= ROW || pt.y >= COL || pt.x < 0 || pt.y < 0)
return false;
//障碍
if (map[pt.x][pt.y])
return false;
//已经走过
if (isFind[pt.x][pt.y])
return false;
return true;
}
打印路径
if (isEnd)
{
printf("找到终点了\n");
while (temp) {
printf("(%d,%d)",
temp->pt.x,
temp->pt.y);
temp = temp->parent;
}
printf("\n");
}
运行结果
比较深度寻路与广度寻路:
深度寻路 判断多 循环少,有回退,适用于宽阔大地图,不一定能找到最短路径,
广度寻路 判断少 循环多,没有回退。适用于小地图,如果你的地图宽阔的话用广度寻路的话就会特别慢。
相同点:都只能走直线,不能走斜线
在一个没有障碍的地图上,从点(0,0)到(9,9)
广度优先寻路算法走过的路径,不同颜色表示不同层
深度优先寻路算法的路径