概述
A* 算法一种图搜索算法,用于寻找一条从起始点到目标点的最短路径。
A* 算法的核心思想是使用启发式方法来评估从当前节点到目标节点的代价,结合从起始点到当前节点的实际代价,来估算总路径代价。
代价函数表示方程
:从起始点到节点 n 的实际代价 :从节点 n 到目标点的估计代价 :从起始点经过当前节点 n 到达目标点的估计代价
维护两个表:Open 表和 Close 表
Open 表
- Open 表用来存放当前未扩展的节点,也就是还没有被探索的节点。
- Open 表中的节点按照一定的规则排序,这里可以使用优先队列实现。对于 A*
算法,排序规则为
值越小的(估计代价越小)优先遍历。
Close 表
Close 表用来存放已扩展的节点,即已被探索的节点。
算法流程
- 将起始点加入 Open 表
- 从 Open 表中选择
值最小的节点进行扩展,并将选定节点从 Open 表移动到 Close 表。 - 如果选定节点的邻居节点不再 Close 表中(未扩展),则计算邻居节点的
值,并加入到 Open 表中。 - 重复执行步骤 2 到 3,直到目标节点被加入到 Close 表中,或者 Open 表为空。
不难看出,A* 算法的核心在于如何设计估计函数
如何确保 A* 算法有效(可接纳性条件)
- 任何节点的分支因子 b 有限
有限的分支因子保证了在每一步搜索中,算法都只会考虑有限数量的后继节点,从而避免了无限搜索的问题
- 任何边(或动作)都有正的代价,即
要求每条边的代价是正的,意味着在搜索过程中,前进到任何节点都需要付出一定的成本,没有免费的移动。这保证了算法在评估路径时能够考虑到每一步的代价,从而找到成本最低的路径。
- 对代价的估计小于真实代价,即
这个条件保证了A*算法的优化性,即算法总是朝着目标前进,而不会因为错误的估计而走弯路
为什么 A* 算法要确保对代价的估计小于真实代价
如果启发式函数
假设起始节点是 start,目标节点是 end,最优解经过
- 但
不一定小于
Golang 实现
定义点
1 | package astar |
定义优先队列
1 | package astar |
A* 算法实现
1 | package astar |
测试
1 | func main() { |