A*算法是路径搜索中的经典算法,也是公认的最优算法之一。
开始:搜索区域
这里假设有人要从A点去往B点,另外有一面墙将两者分开。如下图所示,绿色方块代表A点,红色方块代表B点,蓝色代表分开他们的墙。
图一
首先要注意的是我们这里先将整个搜索区域网格化,以方便路径搜索。这一方法将搜索区域简化为一个简单的2为数组。数组的每个元素代表网格上的一片区域,并且标记为可通过或不可通过两种状态。路径由从A点到达B点所经过的方块来表示。
这些点被称为节点。之所以不直接叫方块是因为区域可以被划分为矩形,六边形,等。而点也不一定是在中心,可以在边缘或其他地方。
开始搜索
一旦我们如上图将搜索区域网格化,将之转化为可操作数量的节点,然后下一步就是找到一个搜索算法找出最短路径。我们从A点出发,搜索递归周围领域,直到到达目标点
开始搜索的步骤如下:
1. 从A点出发并且将其放入到“候选列表”备用。候选列表就像就像是购物清单。现在上面只有一项在清单上,但我们会陆续添加。其中包含一些潜在的路径点。基本上,这个列表包含有待确认的方块。
2. 找到与起始点相邻的所有可到达方块,忽略那些墙,水等其他非法区域。将这些点加入到“候选列表”,存入方法与先前父方块A的存入方法相同。这些父方块会在我们进行路径跟踪回溯的时候派上用场。
3. 从“候选列表”中将A方块删除,并将其加入到“排除列表”,表明在此列表中的方块不需要再去关注。
关于这点,如下图所示,中间的方块是起始点,它周围的亮蓝色边框表明此方块一经被加入到“排除列表”。所有在“候选列表”上的方块都需要进一步检查,他们的边框呈现亮绿色。每一个里面都有一个箭头指向其父节点,这里是起始方框。
图2
接下来,我们在选择“候选列表”中的一个领域然后大致上重复刚才的步骤,如下所述。然后选择拥有最小F值的那个方块
路径评估
在路径选择是关键指标等式描述如下:
F = G + H
这里:
- G= 表示从A点到当前点的所经过的路径长度
- H=从当前点到目标点B的估计路径长度。这经常被描述为“启发式”,有时这样会引起歧义。之所以这么叫是因为这仅仅是一种猜测。事实上在找到路径之前我们并不知道实际路径长度,因为会有如墙,水等东西阻挡。这里给出一种计算H的方法,同时在网上有许多其他计算H值的方法。
我们的路径正式不断的遍历“候选列表”并选择最小F值的点。这个过程会在稍后详细说明。首先来了解我们是如何计算等式的。
如上所述,G是利用先前产生的路径到达当前点所得长度。此例中,出于简化目的,我们定义单元格之间的距离为10,对角单元格距离为14,同时这样做也会大大减少计算量。
有多中计算方法。这里所使用的方法是曼哈顿方法,该方法累计从当前点到目标点在水平方向和垂直方向(忽略对角线方向)所要经过的所有方块数,同时忽略可能遇到的障碍。然后将结果乘以10(单位距离),之所以成为曼哈顿方法,是因为这就像要数从一个地方到另一个地方要走过多少个街区,而同时你有不能斜穿街区。
看完这个描述,你或许会认为所谓的“启发式”不过是将剩余的路径长度粗略的估计为两点间的直线距离。事实上并非如此。我们正是在试图估计实际剩余距离(一般会比实际距离更长),与实际距离越接近,算法越快速,如果估计值过大,就会有可能出现找出的路径不是最短路径的情况。这种情况我们称之为“不可接受启发式”
第一步搜索的F,G,H可表示如下图
图三
继续搜索
继续搜索,我只是从“候选列表”选出最小F值的方块,然后执行如下操作
4) 将其从“候选列表”中删除加入到“排除列表”
5) 检查其领域内方块,排除不可通过方块,并且将没有在“候选列表”中的方块加入到“候选列表”。是当前选中方块成为父方块。
6) 如果领域内存在方块在“候选列表中”中,那么就检查是否从当前点经由那个候选方块是一条更好路径。换句话说,检查那个方块的G值是否会因为我们使用了当前点到达那里而变小,如果不是,什么都不做,另一方面,如果新的路径G值变小了,就将那个候选方块的父节点改为当前点。最后重新计算那个候选节点的F和G值
译者注:
这一步是A*算法较为难理解的一步,这一步的目的在于优化从起始点到候选列表中的点路径,因为在H函数既定的情况下,候选列表中H值就是一定的,此时优化G值可以帮助找到最小的F值。
现在来看一下,在候选列表中的8个方块中,拥有最小F值的是右边中间的方块,所以选择它为下一个方块,在图解中该方块边缘以蓝色高亮。
图4
首先将其从“候选列表”中删除,加入到“排除列表”。然后检查其领域,右边和左边中间的方块都被排除。
领域余下的4个方块都已经在“候选列表”中,所以我们需要检查是否从当前点经由那个候选方块是一条更好路径。计算可以经由当前点并不能改善原有候选列表中方块的G值。所以什么都不做
译者注:G是从起始点到所计算点所经过路径点的G值的和
接下来继续搜索候选列表,找到最小的F值的方块有两个,分别位于右上和右下,这里其实选择哪个没有固定标准,我们选择后加入“候选列表”的那个方块作为当前点,这样做的结果是我们总是优先计算新加入的F值较的候选点,在大部分情况下这有助于我们更快的到达目的地。同样这里采用不同的筛选方法会导致不同的最终路径但拥有相同的路径长度。
所以就选择右下那个方块
图5
这次,我们排除当前方块右边的三个方块,至于右下那个被排除,则是这里选择的穿透策略导致,你也可以选择其他的穿透策略。
重复刚才的步骤知道我们将目标嗲加入到“排除列表”,如下图所示:
图6
那么我们要如何来选择路径呢?答案很简单,我们只要从目标点开始不断的沿着其父方块就可以找回到起始方块。如图中红点方块所示。
图7
A*算法总结
现在将整个步骤总结如下:
1) 将起始点加入到“候选列表”
2) 重复如下步骤:
a) 搜索候选列表的最小F值,将其选为当前点
b) 放入“排除列表”
c) 对于与其相邻的8个方块
-
如果不可通过或其在“排除列表”中,就忽略掉,否则执行下面步骤。
-
如果其不在“候选列表”,将他加入到“候选列表”,将当前点作为其父节点,计算F,G,H
-
如果领域内存在方块在“候选列表中”中,那么就检查是否从当前点经由那个候选方块是一条更好路径。换句话说,检查那个方块的G值是否会因为我们使用了当前点到达那里而变小,如果不是,什么都不做,另一方面,如果新的路径G值变小了,就将那个候选方块的父节点改为当前点。最后重新计算那个候选节点的F和G值
d) 终止条件:
- 目标方块被加入到“排除类表”,这种情况下路径被找到
- 在“候选列表”中的点全部被放到了“排除列表中”,此时路径查找失败,没有通路。
3)保存路径,从目标点开始不断的沿着其父方块就可以找回到起始方块。
最后欢迎大家访问我的个人网站: 1024s