您的位置:首页 > 其它

关于A*寻路算法的认识

2015-04-20 23:58 134 查看
最近要参加学校的APP比赛,我们组做的是一个3D迷宫的小APP,我负责的是迷宫的生成与寻路。

寻路算法选择的是A*寻路算法,具体参考的是下面的这篇博客。

本文主要是谈谈自己对A*算法的理解,具体细节,上文链接以及讲的很详细了。

/article/4844143.html

关于A*算法的实现我是用的广度优先搜索这种比较常见的实现模式。

那么关于这两者之间的关系是怎么样呢?

个人理解的是A*算法其实是一种带有路径信息的有策略的广度优先搜索,我们平常用的广度优先搜索,没有带有路径信息,搜索起来是一种盲目的搜索。

例如,当寻路到A节点时,下一步是以A为中心,分别测试A周围的8个点,并且又以它们为中心,继续向外扩散,以期找到待寻找的点。

这样的搜索带有盲目性,测试了大量的无效的点。

A*算法在每个节点中加入了路径的信息:

F:当前点的路径信息,包含了到当前点到起点与到终点的信息。(F=G+H)

G:当前点到唯一的起点的路径信息。

H:当前点到指定终点的距离信息。

那么我们怎么样通过这些指定的路径信息来避免广度优先搜索的盲目选取下一个路径点而得到一条最小路径呢?

其实我们可以把这看成是一个最小路径的“感染”问题。

F B C D

E A G H

I N K L

如上图:

首先参照上文博客,水平方向移动一格路径代价是10,斜方向移动一格路径代价是14。

起点A的G值初始化0,这个当然,自己到自己的距离是0;其它点中的G初始化为INT_MAX;通过对A的广度搜索,来设置各个节点的G值与父节点。

例:A的八个方向,FBCEGINK,选取出F最小的点,假设为G。

对G的八个方向,BCDAHNKL,我们同样需要设定这8个方向的G值与父节点。这8个方向中与A重叠的有BCNK。

重叠意味着有两条路径,对于K来说,可以是A->K,也可以是A->G->K。

那么怎么样选择呢?

这时我们要判断G的值,哪条路径使得G的值最小,我们就选择它。

G的值是起点A到本节点的路径长度,这是一个累积的值,是前面各个G一路累积(感染)下来的,代表的是当前的路径,我们选择的肯定是使得K的G最小,这样对整个最小路径都是有利的,因为可以一直感染下去。

那么H的作用在哪里呢?

H仅仅是对路径方向的一个大致的判断,上图中,若指定终点在A的右边,那么EFI肯定不会被选中,这样就不用盲目的8个方向都去判断。

终上所述:

G和H的作用共同体现于F中,每次我们都是在广度搜索中去寻找F最小的点,然后根据G的值,设置下一个广度搜索中的节点的父节点,父节点永远是使得子节点中的G值最小。(到起点A的路径最短)。

自己写的A*的核心函数代码,测试curr节点的周围8个节点,并且设置路径及父节点信息,其余的部分则是广度优先搜索的框架,这里不再写出来。

void getSurrroundPoints(point& curr, list<point>& result)
{
int x = curr.m_x;                              //curr坐标信息
int y = curr.m_y;

for (int i = x-1;i <= x+1; i++)
{
for (int j = y - 1; j <= y + 1; j++)       //8个方向
{
if (i == x && j == y)                  //循环到自己,跳过此次循环
continue;

if ( find_if(closeList.begin(), closeList.end(), pointEqualLocation(i, j)) == closeList.end()  //当前节点还没有被检查过
&&canReach(i, j))                                                                          //当前节点不是障碍物
{
if (x == i || y == j)      //上下左右四个方向 g=10
{
if ((curr.m_g + 10) >= point_ptr[i][j].m_g)
{
//start到(i,j)的 不必经过curr
//什么也不做,保留原来的路径信息与父节点
}
else
{                    //start到(i,j)的 经过curr路径会更小
//更新路径信息 更改父节点
point_ptr[i][j].m_g = curr.m_g + 10;      //更新节点中的G值
point_ptr[i][j].m_fx = curr.m_x;          //设置父节点
point_ptr[i][j].m_fy = curr.m_y;

}
}
else                     //斜方向 g=14;
{
if ((curr.m_g + 14) >= point_ptr[i][j].m_g)
{
//start到(i,j)的 不必经过curr
//什么也不做,保留原来的路径信息与父节点
}
else
{                    //start到(i,j)的 经过curr路径会更小
//更新路径信息 更改父节点
point_ptr[i][j].m_g = curr.m_g + 14;    //更新节点中的G值
point_ptr[i][j].m_fx = curr.m_x;        //设置父节点
point_ptr[i][j].m_fy = curr.m_y;

}
}
point_ptr[i][j].m_h = abs(endPoint_x - i) + abs(endPoint_y - j);  //计算到终点的距离
point_ptr[i][j].m_f = point_ptr[i][j].m_g + point_ptr[i][j].m_h;  //F=G+H

result.push_back(point_ptr[i][j]);                  //放到链表中 等待下次的检查
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: