读完本文,你不仅学会了算法套路,还可以顺便解决如下题目:

前置知识
一句话总结

A* 算法主要用于解决二维网格中的点对点最短路径问题,通过引入启发函数,让算法有方向性地向终点搜索,提高搜索效率。

标准的 BFS 算法 可以计算无权图的最短路径。

Dijkstra 算法 借助优先级队列,可以高效计算不包含负权重的加权图的最短路径。

那你有没有思考过,对于无权图,如果我非要用 Dijkstra 算法,会发生什么?是否会有性能提升呢?

让我们探讨二维数组中的寻路问题,比如迷宫寻路,二维数组的左上角为起点,右下角为终点,计算最短路径。

这个场景中,可以把二维数组的每个位置看作一个节点,相邻位置之间有边相连,边的权重都是 1,也就是无权图。

一般的做法是用标准的 BFS 遍历算法,从起点开始,一层一层暴力搜索就行了,第一次到终点时就是最短路径。

如果我们用 Dijkstra 算法,不仅没有性能提升,反而比 BFS 算法更慢。

原因很简单,边权重都是 1,那么早入队的节点权重小,晚入队的节点权重大,因此节点出队的顺序就是先进先出(和普通队列一样),效果等同于标准 BFS 算法。反而因为优先级队列产生额外的维护成本,导致时间复杂度比标准 BFS 更高(O(ElogE)O(E \log E) vs O(E)O(E))。

比如这个迷宫小游戏可以设置求解迷宫的算法,你可以分别设置 Dijkstra 算法和 BFS 算法求解迷宫,就能发现它们的搜索路径完全一致:

迷宫地图生成

那么,对于这个场景是否有优化呢?其实有一个思路:

既然终点在右下角,我们可以优先向右下角搜索,这样有更大概率更容易到达终点;反之,尽量不要往左上角走,因为那样大概率会南辕北辙绕远路。

这就是 A* 算法的核心思想:不仅仅考虑节点距起点的距离,也要考虑节点距终点的距离

A* 算法的核心思想

具体地,对于任意节点 x,我们定义三个量: