A*算法浅谈

来源:互联网 发布:js qq分享回调地址 编辑:程序博客网 时间:2024/06/06 16:27

在纠结了两天的A*算法之后,今天想在此总结下这个传说中的A*算法。。(大牛尽可以无视之)

启发式搜索:

在介绍A*算法之前还是先介绍一下启发式搜索的一些概念。启发式搜索的发明初衷是考虑到对一些搜索问题,搜索的方向具有一定的启发信息,即对每一次搜索的方向具有一定的智能性,不是随机地(或是目盲地)选择其中的一个方向进行搜索,而是通过挖掘问题自身的一些信息来“引导”接下去的搜索。假设我们搜索的起点为start,搜索的终点(即目标点)为end。对每一个状态s,我们定义s的估价函数:F(s) = H(s) + G(s) ,作为当前s状态的启发信息。G(s)为从start点到s状态的实际距离(通常都是以广度优先搜索的深度来作为G(s)的值),H(s)是s状态距离目标状态的估计代价,正是这个函数体现了搜索的自能化。通常启发式搜索的性能由H(s)的好坏决定。H函数必须要是相容的,所谓相容就是要求对于任何两个状态s1,s2,都有H(s1) <= H(s2) + C(s1,s2) (其中C(s1,s2)表示有状态s1转移到s2的实际代价),这个式子也说明:下界H的减少值最多等于状态转移的实际代价。F函数必须也是相容的,这点由H函数是相容很容易就可以推出来。 

A*算法:

A*算法实际就是一种BFS,(当然也有它的强化版,IDA*,是基于迭代加深的A*算法),只不过这种BFS并不是我们所之前熟悉那种BFS,我们之前熟悉的BFS,可以说是A*算法的特例,因为它在搜索的过程中不携带任何的启发信息,即H = 0 ,因此它是最差的A*算法。回到A*算法上来,前面说A*算法其实就是一种BFS,所不同的是A*算法在扩展结点的时候,不像BFS那样盲目地扩展每一个结点,而是有“方向性”地扩展某些结点,这个“方向性”的判断就是依据F(s)函数,每次选取F(s)值最小的结点进行扩展。在A*算法中,需要维护两个表,OPEN表和CLOSED表,OPEN表中存放的是待扩展的结点,CLOSED表中存放的是已完成扩展的结点。每次扩展结点的时候都是在OPEN表中选择一个F值最小的结点进行扩展其子结点,对于其子结点有三种可能:(1)、子结点即不在OPEN表中,也不在CLOSED表中,说明该结点之前没有遇到过,此时计算出该结点的G值和H值,并求出相应的F值,将此结点加入到OPEN表中;(2)、子结点在OPEN表中,由于我们扩展的是F值最小的结点,因此这种情况还是有可能出现的。对于这种情况,我们需要比较该结点之前的G值和由现在的方式到达时的G值的大小,如是新G值更小,则更新该点的F值;否则不更新。 (3)、子结点在CLOSED表中,对于这种情况,由于该结点已经关闭,因此不考虑对其操作。

以下就通过一个例子来说明A*算法的具体实现过程:

考虑下面的一个简单搜索,每个方格都被编了一个唯一的号,绿色的方格代表的是起点,红色的方格代表的是终点,蓝色方格代表的是障碍物,黑色的方格代表可以走的路。要求从起点寻找一条最优的路径,规定只能向up、down、left、right四个方向走。下面我们将结合A*算法来说明这个过程。




首先在本例中,我们设置的启发函数H为: 终点所在行减去当前格所在行的绝对值   与   终点所在列减去当前格所在列的绝对值  之和,而G值为从当前格的父亲格移动到当前格的预估移动耗费,在这里我们设定一个基数10,每个H和G都要乘以10,这样方便观察。(并不是只有这一个唯一的启发函数可采纳,网上还有很多其他可行的启发函数。)

开始搜索,为了保持路径,我们需要设置一个从子结点指向其父结点的指针。起点的指针指向NULL,然后将起点的G值设置为0,再装进OPEN表里面,然后将起点作为父亲结点的周围4个点20,28,30,38(因为我们地图只能走4个方向,如果是8方向,则要加个点进去)都加进OPEN表里面,并算去每个结点的H值,然后再将起点从OPEN列表删除,放进CLOSED表中,我们将放进CLOSED表的所有方格都用浅蓝色线条进行框边处理,所以这次搜索以后,图片变为如下格式,其中箭头代表的是其父结点。




其中每个格子的左下方为G值,右下方为H值,左上方为F值(F = G + H ),我们拿28号格子为例来讲解一写F值的算法,首先因为终点33在4行7列,而28在4行2列,则行数相差为0,列数相差为5,总和为5,再乘以我们先前定的基数10,所以H值为50,又因为从28的父结点29移动到28,长度为1格,而29号为起点,G值为0,所以在父亲结点29的基础上移动到28所消耗的G值为(0 + 1) *10 = 10,0为父亲结点的G值,1为从29到28的消耗。

当前OPEN表中的值: 20,28,30,38     当前CLOSED表中的值: 29

现在我们开始寻找OPEN列表中F值最低的,得出结点30的F值最低,且为40,然后将结点30从OPEN表中删除,然后再加入到CLOSED表中,然后在判断结点30周围4个结点,因为结点31为障碍,结点29存在于CLOSED表中(在CLOSED表的结点,我们将不做考虑。),我们将不处理这两点,只将21和39号结点加入OPEN表中,添加完后地图变为下图样式

当前OPEN表中的值: 20,28,38,21,39   当前CLOSED表中的值: 29,30




接着我们重复上面的过程,寻找OPEN表中F值为低的值,我们发现OPEN表中所有结点的F值都为60,我们随即取一个结点,这里我们直接取最后添加进OPEN表中的结点,这样方便访问(因为存在这样的情况,所有从一个点到另外一个点的最短路径可能不只一条),我们取结点39,将他从OPEN表中删除,并添加进CLOSED表中,然后观察39号结点周围的4个结点,因为40号结点为障碍,所以我们不管它,而30号结点已经存在与OPEN表中了,所以我们要比较下假设39号结点为30号结点的父结点,30号结点的G值会不会更小,如果更小的话我们将30结点的父结点改为39号,这里我们以39号结点为父结点,得出30号结点的新G值为20,而30号结点原来的G值为10,并不比原来的小,所以我们不对30号进行任何操作,同样的对38号结点进行上述操作后我们也不对它进行任何操作,接着我们把48号结点添加进OPEN表中。

当前OPEN表中的值: 20,28,38,21,48   当前CLOSED表中的值: 29,30,39

以后的过程都是重复的,直到搜索到终点。然后我们通过父结点就可以得出一条最优的路径了。。


我理解的A*算法的大体思路就是这些了 ,若有写得不对的地方,还请各位大牛指点哈~~ !


PS:今天真的好郁闷,又要开始迷失了。。。



原创粉丝点击