背景
在A∗算法出现之前,人们都在用DFS和BFS进行搜索,然而,这两种算法在展开子节点时都属于盲目型搜索,也就是说,它不会选择在下一次搜索中更优的那个节点,继而借此跳转到该节点进行下一步的搜索,而是盲目全局搜索。如果运气不好,在此情形中,均需要试探完整个解集空间,显然,DFS和BFS只适用于问题规模不大的搜索问题中。 然而,1968年的一篇论文“P. E. Hart, N. J. Nilsson, and B. Raphael. A formal basis for the heuristic determination of minimum cost paths in graphs. IEEE Trans. Syst. Sci. and Cybernetics, SSC-4(2):100-107, 1968”,打破了这个僵局,从此,一种精巧、高效的算法------A*算法横空出世了,而且还在好多领域取得了不错的应用。
算法介绍
A∗算法属于启发式搜索算法,在寻路方面,它可以是在图形平面上,有多条路径,求出最低成本的算法,是非常流行的该类搜索算法中的一个,它一般被用于路径优化领域,例如导航、游戏里面的人物移动等。它的特别之处是在检查最短路径中时,检查每个可能符合需要的节点时都引入了全局的信息,然后对当前节点距终点的距离做出估计,并作为评价该节点处于最短路线上的可能性的量度。
算法搜索过程
核心
两个集合:Open,Closed和一个公式:f(n)=g(n)+h(n)。其中Open,Closed都是存储节点的集合,Open存储可到达的节点,Closed存储已经到达的节点;而公式f(n)=g(n)+h(n)则是对节点价值的评估,g(n)代表从起点走到当前节点的成本,也就是走了多少步,h(n)代表从当前节点走到目标节点的距离,即不考虑障碍的情况下,离目标还有多远。至于f(n),则是对g(n)和h(n)的综合评估,我们应该尽量选择步数更少,离目标更近的节点,那么f(n)的值越小越好。
搜索思路
开始时,Closed表为空,Open表仅包括起始节点,每次迭代中,A∗算法将Open表中具有最小代价之的节点去除进行检查,检查后的节点放入Closed表,如果这个节点不是目标节点,那么考虑该节点的所有相邻节点。对于每个相邻节点按下列规则处理;
- 如果相邻节点既不在Open表中,又不在Closed表中,则将它加入Open表中;
- 如果相邻节点已经在Open表中,并且新的路径具有更低的代价值,则更新它的信息;
- 如果相邻节点已经在Closed表中,那么需要检查新的路径是否具有更低的代价值,如果是,那么将它从Closed表中移出,加入到Open表中,否则忽略。(这里需要检查Closed表是因为要防止由于h(n)计算不准确而导致的误差)
重复上述步骤,直到到达目标节点。如果在到达目标之前,Open表就已经变空,则意味着在起始位置和目标位置之间没有可达的路径。
算法流程图

算法正确性证明
前置知识
符号说明:
-
g(n)表示从点st到达节点n的当前最小代价。
-
g∗(n)表示从节点st到节点n的实际最小代价。
-
h(n)表示从节点n到目标节点end的预估代价。
-
h∗(n)表示从节点n到目标节点end的实际最小代价。
-
f(n)=g(n)+h(n) 。这里f(n)的含义为从初始节点st出发经过节点n再到达目标节点end的最小代价的预估。
-
f∗(n)。实际的最短路径长度。
-
OPEN LIST(开放列表),CLOSE LIST(封闭列表)。
算法本身性质一: 每次选择的节点是f(n)=g(n)+h(n)最小的节点。而且,OPEN LIST上任一具有f(n)<f∗(st)的节点n,最终都将被A∗选作扩展节点。(下面定理推论2.1)
算法本身性质二: h(n)≤h∗(n),预估代价小于实际最小代价。
开始证明
先证明,如果有解,那么算法一定可以找到:
定理1: 对有限图,如果从初始节点st到目标节点end有路径存在,则A*算法一定成功结束。
- 首先证明算法必定结束。由于搜索图为有限图,如果算法能找到解,则会成功结束;如果算法找不到解,那么必然会因为OPEN LIST 为空而结束。因此A算法必然会结束。
- 然后证明算法一定会成功结束。由于至少存在一条由初始点到目标点的路径,设此路径为Pst=st(v0)→v1→v2⋯→end(vm) 那么算法开始时,节点v0在OPEN LIST 中,而且路径中任一节点vk 离开OPEN LIST 后,其后继节点vk+1一定会在这之前进入OPEN LIST 。这样在OPEN LIST 变空之前,目标节点必然会出现在OPEN LIST 中。因此,算法必定会结束。
引理1: 对无限图,若有从初始节点st到目标节点end的路径,则A∗不结束时,在OPEN LIST 中即使最小的一个f(vn)值也将增到任意大,或有f(vn)>f∗(st)。
- 设d∗(vn) 是A∗生成的从初始节点v0到节点vn的最短路径长度(这里的长度指的是要经过多条边),由于搜索图中每条边的代价都是一个正数,令这些正数中最小一个数是e,则有g∗(vn)≥d∗(vn)×e。(g∗(vn)是源点到vn的最小代价,d∗(vn)是源点到vn的最小长度,长度乘以所有边中的最小代价,得到的肯定比从源点到n的最小代价要小)
- 又因为是最佳路径的代价,所以g(vn)≥g∗(vn)≥d∗(vn)×e
- 又因为h(vn)≥0,所以f(vn)=g(vn)+h(vn)≥g∗(vn)≥d∗(vn)×e
- 所以如果A∗算法不终止,从OPEN LIST 中选出的节点必将拥有任意大的d∗(vn)值,因此,也将具有任意大的f值。
引理2: A∗结束前的任意时刻,OPEN LIST 中总是存在结点vk ,它是从初始结点st到目标节点end 的一个节点,且满足f(vk)<f∗(vk) 。
设初始点st到目标end 的最佳路径序列Pst=st(v0)→v1→v2⋯→end(vm)。
- 算法开始的时候,节点st在OPEN LIST中,当节点st离开OPEN LIST 进入CLOSE LIST中时,节点v1进入OPEN LIST 。因此,A∗没有结束之前,在OPEN LIST 中,必然是最佳路径上的节点。设这些节点排在最前面的节点为vk,则有:f(vk)=g(vk)+h(vk)
- 由于vk在最佳路径上,故有g(vk)=g∗(vk),从而f(vk)=g∗(vk)+h(vk)。
- 又由于A∗算法性质二h(vk)≤h∗(vk),故有,f(vk)≤g∗(vk)+h∗(vk)=f∗(vk)。
- 因为在最佳路径上的所有节点的f∗值都相同,因此有f(vk)≤f∗(vk)。
定理2: 对无限图,若从初始节点st到目标节点end有路径存在,则A∗一定成功结束。
反证法:
- 使用引理1:假设A∗不结束,在OPEN LIST中即使最小的一个f(n)值也将增到任意大,或有f(n)>f∗(s)
- 根据引理2:在A∗结束前,必存在节点n,使得f(n)<=f∗(s),所以,如果A∗不结束,将导致矛盾,A∗算法只能成功结束。
推论2.1:OPEN LIST上任一具有f(n)<f∗(st)的节点n,最终都将被A∗选作扩展节点。
- 由定理2,知A∗一定结束,由A∗的结束条件,OPEN LIST中f(end)最小时才结束。
- 而f(end)≥f∗(end)=f∗(st),所以f(n)<f∗(st) ,均被扩展,得证。
根据定理一和定理二可知,不论是在无向图还是在有向图中,如果有解一定可以被A∗算法找到
再证明,算法找的的解一定是最优解:
引理一: 已知从初始节点st到目标节点end的一条最短路径Pst,路径上任意一点n,g∗(n)=∣Pst(st→n)∣。
已知一条st到n的路径长度为∣Pst(st→n)∣,根据g∗(n)的最小性g∗(n)≤∣Pst(st→n)∣。
利用反证法证明如下:
假设:g∗(n)<∣Pst(st→n)∣。
那么,意味着存在一条路径P′,该路径从st到n的长度∣P′(st→n)∣<∣Pst(st→n)∣。
则∣P′(st→n)∣+∣Pst(n→end)∣<∣Pst(st→end)∣。这与Pst为从st到end的最短路径矛盾。
所以原假设g∗(n)<∣Pst(st→n)∣不成立,因此g∗(n)=∣Pst(st→n)∣得证。
引理二: 已知从初始节点st到目标节点end的一条最短路径Pst,路径上任意一点n,h∗(n)=∣Pst(n→end)∣。(证明思路和引理1相同)
已知一条n到end的路径长度为∣Pst(n→end)∣,根据h∗(n)的最小性h∗(n)≤∣Pst(n→end)∣。
利用反证法证明如下:
假设:h∗(n)<∣Pst(n→end)∣。
那么,意味着存在一条路径P′,该路径从st到n的长度∣P′(n→end)∣<∣Pst(n→end)∣。
则∣Pst(st→n)∣+∣P′(n→end)∣<∣Pst(st→end)∣。这与Pst为从st到end的最短路径矛盾。
所以原假设h∗(n)<∣Pst(n→end)∣不成立,因此h∗(n)=∣Pst(n→end)∣得证。
引理三: 对于任意节点n,g(n)=g∗(n)时f(n)最小。
证明:已知f(n)=g(n)+h(n)。对于h(n),在寻路前就已经确定,是一个定值。因此,argmin(f(n))=argmin(g(n)+h(n))=argmin(g(n))+h(n) 。也就是说f(n)的值只有在更新g(n)时才会变。而g(n)最小值是g∗(n),所以对节点n而言,g(n)=g∗(n)时f(n)最小。
我们利用反证法进行证明:
假设:A∗算法求出的解不是最优,那么我们通过A∗算法寻到了一条从st到end的路径PA∗,而这条路径并不是最短路径。
那么则存在最短路径Pst,有∣Pst∣<∣PA∗∣。设最短路径Pst=st(v0)→v1→v2⋯→end(vm)。
以下利用数学归纳法
归纳奠基:
当到节点vn,n=0时: 把节点st放入CLOSE LIST中,把st相邻节点放入OPEN LIST中并更新g值。这一步后v1显然应该在OPEN LIST中,并且因为节点v1为最短路径Pst上的节点,根据引理一,g∗(v1)=∣Pst(st→v1)∣。这里发现更新g(v1)时也是根据节点st到节点v1的边的长度,即g(v1)更新为∣Pst(st→v1)∣,这时有g(v1)=g∗(v1)。根据引理三,这时的f(v1)就是最小值了,以后不会再发生变化。
利用算法本身性质一、引理一、引理二,有f(v1)=g(v1)+h(v1)=g∗(v1)+h(v1)≤g∗(v1)+h∗(v1)=∣Pst∣<∣PA∗∣。也就是f(v1)<f(end)也成立。由A∗算法的性质一可以知道,v1节点一定可以在结束之前被选中,用来更新数据。
当到节点vn,n=1时: 若v2不在OPEN LIST或CLOSE LIST中,直接更新g(v2);若在OPEN LIST或CLOSE LIST中,接下来由g(v2)与g(v1)+∣Pst(v1→v2)∣的大小关系,判断是否会通过通过v1对g(v2)进行更新。
g(v2)=g(v1)+∣Pst(v1→v2)∣=g∗(v1)+∣Pst(v1→v2)∣=∣Pst(st→v1)∣+∣Pst(v1→v2)∣=∣Pst(st→v2)∣=g∗(v2)
根据引理一,此时的g(v2) 是最小的,所以若g(v2)更新,则g(v2)=g∗(v2)。
- 若不更新,则说明g(v2)≤g(v1)+∣Pst(v1→v2)∣=g∗(v2),又因为g∗(v2)≤g(v2),则g(v2)=g∗(v2)。
这意味着通过v1对节点v2计算g(v2)后,无论是否更新,g(v2)都会取g∗(v2)。那么把v1放入CLOSE LIST后,无论v2在CLOSE LIST或OPEN LIST中,还是不在,最终的g(v2) 都等于g∗(v2)。根据引理三,这时的f(v2)就是最小值了,以后不会再发生变化。
归纳假设:对于节点vn,n=k时,满足g(vk)=g∗(vk),且以后不会发生变化。
归纳递推:对于节点vn,n=k+1,k≤m−1时:
利用算法本身性质一、引理一、引理二,有f(vk)=g(vk)+h(vk)=g∗(vk)+h(vk)≤g∗(vk)+h∗(vk)=∣Pst∣<∣PA∗∣。也就是f(vk)<f(end)也成立。由A∗算法的性质一可以知道,vk 节点一定可以在结束之前被选中,用来更新数据。
若vk+1不在OPEN LIST或CLOSE LIST中,直接更新g(vk+1);若在OPEN LIST或CLOSE LIST中,接下来由g(vk+1)与g(vk)+∣Pst(vk→vk+1)∣的大小关系,判断是否会通过通过vk对g(vk+1)进行更新。
g(vk+1)=g(vk)+∣Pst(vk→vk+1)∣=g∗(vk)+∣Pst(vk→vk+1)∣=∣Pst(st→vk)∣+∣Pst(vk→vk+1)∣=∣Pst(st→vk+1)∣=g∗(vk+1)
根据引理一,此时的g(vk+1) 是最小的,所以若g(vk+1)更新,则g(vk+1)=g∗(vK+1)。
- 若不更新,则说明g(vk+1)≤g(vk)+∣Pst(vk→vk+1)∣=g∗(vk+1),又因为g∗(vk+1)≤g(vk+1),则g(vk+1)=g∗(vk+1) 。
这意味着通过vk 对节点vk+1计算g(vk+1)后,无论是否更新,g(vk+1)都会取g∗(vk+1)。那么把vk 放入CLOSE LIST后,无论vk+1在CLOSE LIST或OPEN LIST中,还是不在,最终的g(vk+1) 都等于g∗(vk+1)。根据引理三,这时的f(vk+1)就是最小值了,以后不会再发生变化。
综上所述:∀k∈Z,0≤k≤m,满足g(k)=g∗(k),且以后不会发生变化。
因此,最后从OPEN LIST 中取出end(vm)节点的时候,∣PA∗∣=f(vm)=g(vm)+h(vm)=g∗(vm)+h(vm)=g∗(vm)=∣Pst∣。这是一条根据A∗算法找到的路径PA∗。这显然与我们最初的假设“通过A∗算法找到的路径不是最小值,也就是∣Pst∣<∣PA∗∣”矛盾。所以假设不成立,通过A∗算法找到的就是最短路径。