BFS(广度优先搜索)算法和a*算法详解和对比
算法概述
BFS(广度优先搜索)和A*(A-Star)这两种算法都是用于图或网格中寻找路径的经典算法,但它们的策略、效率和适用场景有很大不同。
1. BFS(广度优先搜索)算法介绍
基于JavaScript实现的 BFS(广度优先搜索)路径搜索算法代码实现:《基于JavaScript实现BFS(广度优先搜索)路径搜索算法代码,并通过动画动态展现BFS 的搜索过程》
核心思想
BFS的核心是“地毯式”层层推进的搜索。它从起点开始,优先访问所有相邻的节点,然后再访问这些相邻节点的相邻节点,以此类推,直到找到目标节点。
算法步骤
将起点放入一个 队列(Queue) 中,并标记为已访问。
从队列中取出最前面的节点(即最先进入的节点,FIFO原则),我们称之为“当前节点”。
检查这个“当前节点”是不是目标节点。如果是,搜索结束,回溯路径。
如果不是,就将这个“当前节点”的 所有未被访问过的相邻节点 放入队列的末尾,并标记为已访问,同时记录这些新节点是从哪个节点过来的(用于最后回溯路径)。
重复步骤2-4,直到队列为空(表示所有可达节点都已访问过)或找到目标。
特点
-
完备性:如果路径存在,BFS一定能找到。
-
最优性:在无权图(所有边的代价相同)中,BFS找到的路径一定是最短路径。
-
效率:它需要遍历所有从起点出发、路径长度小于等于目标路径的节点,因此在搜索空间大时非常耗时和耗内存。
-
“盲目”搜索:它没有方向性,只是机械地向四周扩散,不知道目标在哪。
可视化比喻
想象一滴墨水在清水中匀速向四面八方扩散。
2. A*(A-Star)算法
核心思想
A*算法是一种启发式搜索或智能搜索。它不像BFS那样盲目,而是会“有方向地”朝着目标进行搜索。它通过一个代价函数 F(n) 来决定下一步探索哪个节点最有希望。
关键概念
g(n):从起点到当前节点 n 的实际代价。
h(n):从当前节点 n 到目标点的预估代价。这个就是“启发函数”。A*算法的效率和质量很大程度上取决于h(n)的选择。
f(n):节点的总预估代价,f(n) = g(n) + h(n)。
A*算法总是优先选择 f(n) 值最小的节点进行扩展,因为它认为这条路径最有可能是最短路径。
算法步骤
将起点放入一个 优先队列(Priority Queue,通常是最小堆) 中,其 f(start) = g(start) + h(start)。g(start) 通常为0。
从优先队列中取出 f(n) 值最小的节点,作为“当前节点”。
检查这个“当前节点”是不是目标节点。如果是,搜索结束,回溯路径。
如果不是,就将这个“当前节点”的 所有可达的相邻节点 进行如下处理:
计算相邻节点的 g 值(当前节点的g值 + 到相邻节点的移动代价)。
如果这个相邻节点是第一次被访问,或者我们找到了一条到达它的g值更小的新路径,那么就更新这个节点的g值,并计算其f值,然后将其(或更新其在优先队列中的位置)放入优先队列,同时记录它的父节点为当前节点。
重复步骤2-4,直到队列为空或找到目标。
特点
-
完备性:在大多数情况下,如果路径存在,A*也能找到。
-
最优性:只要启发函数 h(n) 是可采纳的,即 h(n) 永远不会高估 从节点n到目标的实际代价,那么A*找到的路径就是最优的。常见的可采纳启发函数有曼哈顿距离(适用于只能上下左右移动的网格)和欧几里得距离。
-
高效性:相比于BFS,A*通过启发函数极大地减少了需要探索的节点数量,因此通常快得多。
“有信息”的搜索:它利用了对目标位置的信息来指导搜索方向。
可视化比喻
想象一个寻路者,他不仅知道自己走了多远(g(n)),还手里拿着一个指南针,能大致估算自己离终点还有多远(h(n))。他总是选择“已走距离 + 估算剩余距离”最短的那个方向前进。
BFS(广度优先搜索算法)和a*算法有什么区别
广度优先搜索(BFS)和A*算法虽然都是非常常用的图搜索算法,但它们在目标、效率和应用场景上有显著区别。以下是它们的核心区别:
1. 搜索策略
-
BFS:盲目搜索:逐层扩展所有可能的节点,不考虑目标位置或路径代价。
按层遍历:先访问起点的所有邻居,再访问邻居的邻居,依此类推。 -
A*:启发式搜索:优先扩展“最有希望”的节点(通过代价函数
f(n)=g(n)+h(n) 判断)。
目标导向:倾向于向目标方向搜索,减少无用节点的扩展。
g(n): 从起点到当前节点的实际代价。
h(n): 启发式函数,估计当前节点到目标的代价(如曼哈顿距离、欧几里得距离)。
2. 完备性与最优性
-
BFS:完备:如果解存在,一定能找到(在有限图中)。
最优(仅限无权图):在无权图中找到的路径是最短步数;但在带权图中可能非最优。 -
A*:完备:如果解存在且启发函数
h(n) 可容(admissible,即不高估实际代价),则一定能找到解。
最优:当 h(n) 可容且一致(consistent)时,A* 找到的路径是最优的。
3. 时间复杂度与空间复杂度
-
BFS:时间/空间复杂度:
O(bd),其中 b 是分支因子,d 是解的深度。
需要存储所有已访问节点,内存消耗大(尤其是大规模图)。 -
A*:时间复杂度:取决于启发函数的质量。最优情况下可降至 O(d),最差仍为 O(b d)。
空间复杂度:与BFS类似,但通过启发式剪枝可能减少部分节点扩展。
4. 适用场景
BFS:无权图的最短路径问题(如迷宫的最少步数)。
需要遍历所有可能状态的问题(如状态空间搜索)。
A*:带权图的最优路径问题(如地图导航、游戏AI)。
需要高效搜索的场景,尤其是当启发函数能有效估计代价时。
5. 启发式信息的使用
BFS:完全不使用启发式信息,完全依赖拓扑结构。
A*:依赖启发函数 h(n) 引导搜索方向,函数质量直接影响效率。
直观对比示例
假设要在网格地图中从起点 S 到目标 G:
BFS会像“涟漪扩散”一样均匀探索所有方向,直到碰到目标。
A*会优先探索靠近目标的路径(如绕过障碍物走直线),减少无用搜索。
总结
| 特性 | BFS | A* |
|---|---|---|
| 搜索策略 | 盲目、按层扩展 | 启发式、优先最优路径 |
| 最优性 | 仅无权图最短路径 | 带权图最优路径(需 h(n) 可容) |
| 空间开销 | 高(存储所有节点) | 类似BFS,但可能剪枝 |
| 适用场景 | 无权图、状态枚举 | 带权图、路径优化 |
选择依据:
如果问题无权且需最短步数,BFS简单可靠。
如果问题带权或需高效搜索,A*更优(需设计合适的 h(n))。
