A*搜索算法
A*搜索算法是一种广泛应用于路径规划和图遍历的高效算法。它结合了Dijkstra算法的完备性(保证找到最短路径)和贪心最佳优先搜索算法的启发性(倾向于探索目标方向),通过评估函数来指导搜索方向,从而在大多数情况下比两者都更快。
1. 核心思想:评估函数 f(n)
A*算法的核心在于它为图中的每个节点 n 计算一个评估函数:
f(n) = g(n) + h(n)
g(n):这是从起始节点到当前节点n的实际代价。这个值是已知且准确的,就像在Dijkstra算法中记录的距离一样。h(n):这是从当前节点n到目标节点的预估代价,也称为启发式函数。这个值是一个估计,并不是精确值。h(n)的设计质量直接决定了A*算法的效率。
算法的目标是找到一条路径,使得路径终点(目标节点)的 f(n) 值最小。
2. 算法流程详解
算法需要维护两个集合:
- 开放列表:一个优先队列(通常是最小堆),存放所有已发现但尚未评估的节点。节点按照其
f(n)值进行排序,f(n)值最小的节点拥有最高优先级。 - 关闭列表:一个集合(如哈希表),存放所有已经评估过的节点。这些节点的最优路径已被确定,无需再次处理。
步骤如下:
-
初始化:
- 将起始节点
S加入开放列表。设置S的g(S) = 0,并计算其启发值h(S)和评估值f(S) = g(S) + h(S)。 - 关闭列表初始化为空。
- 将起始节点
-
循环开始:当开放列表不为空时,循环执行以下步骤:
a. 选择当前节点:从开放列表中取出f(n)值最小的节点,我们称其为当前节点N。如果开放列表使用优先队列,这就是出队操作。
b. 目标测试:如果当前节点N就是目标节点T,那么搜索成功。我们可以通过从T反向追踪父节点来重构路径。
c. 扩展节点:将节点N从开放列表移至关闭列表,表示已评估。然后,遍历N的所有邻居节点M。
d. 处理邻居节点M:对于每个邻居M:
* 跳过已关闭节点:如果M在关闭列表中,直接忽略它,因为它的最短路径已经确定。
* 计算临时g值:计算从起点经过N到达M的代价:temp_g = g(N) + cost(N, M),其中cost(N, M)是从N到M的边的权重。
* 判断是否发现新路径或更优路径:
* 如果M不在开放列表中,说明它是新发现的节点。将M加入开放列表,设置其g(M) = temp_g,计算f(M) = g(M) + h(M),并记录N为M的父节点。
* 如果M已经在开放列表中,说明我们找到了一条到达M的新路径。比较新路径的代价temp_g和之前记录的g(M):
- 如果temp_g < g(M),说明新路径更优。于是更新M的g(M)为temp_g,并相应更新f(M)。同时,将M的父节点设置为N。由于f(M)改变了,需要调整开放列表(优先队列)中M的位置。
- 如果temp_g >= g(M),说明新路径更差或一样,不做任何处理。 -
循环结束:如果开放列表为空,意味着已经遍历所有可达节点但仍未找到目标节点,此时搜索失败,不存在从起点到目标的路径。
3. 启发式函数 h(n) 的关键性质
启发式函数 h(n) 的选择至关重要,它必须满足以下条件以保证A*算法的正确性和效率:
-
可采纳性:
h(n)永远不能高估从当前节点n到目标节点的实际最小代价。即h(n) <= h*(n),其中h*(n)是真实的实际代价。这个性质保证了A*算法找到的路径一定是最短路径。- 例子:在网格地图中,曼哈顿距离(只能上下左右移动)或直线距离(欧几里得距离)都是可采纳的,因为它们都是两点间最短路径的乐观估计。
-
一致性(或称单调性):对于任意节点
n和其邻居节点m,满足h(n) <= cost(n, m) + h(m)。这可以理解为启发函数不会“欺骗”你,认为从n到目标的代价比先走到邻居m再到目标的代价还要大。一致性是可采纳性的更强形式。如果h(n)是一致的,那么当A*算法扩展一个节点时,到达该节点的路径一定是最优路径,它的g(n)值无需再次被更新,算法效率更高。
4. 一个简单的例子
假设有一个4x4的网格,起点在(0,0),目标点在(3,3)。我们可以使用曼哈顿距离作为启发式函数:h(n) = |x_n - x_goal| + |y_n - y_goal|。
- 起点(0,0):
g=0,h=6,f=6。加入开放列表。 - 取出f值最小的(0,0)进行扩展。检查其邻居(0,1)和(1,0)。
- (0,1):
g=1,h=5,f=6。加入开放列表。 - (1,0):
g=1,h=5,f=6。加入开放列表。
- (0,1):
- 此时开放列表中有(0,1)和(1,0),f值都是6。假设我们取出(0,1)进行扩展。检查其邻居(0,2), (1,1), (0,0)。
- (0,2):
g=2,h=4,f=6。加入开放列表。 - (1,1):
g=2,h=4,f=6。加入开放列表。 - (0,0)在关闭列表中,忽略。
- (0,2):
- 算法持续进行,每次都会优先扩展那些看起来离目标更近(f值小)的节点,直到最终找到目标点(3,3)。
总结
A*搜索算法通过结合已知代价 g(n) 和预估代价 h(n),智能地引导搜索方向,在保证找到最优路径的前提下,大幅减少了需要探索的节点数量,是解决最短路径问题非常强大且实用的工具。