mobile wallpaper 1 mobile wallpaper 2 mobile wallpaper 3
1317 字
4 分钟
四大传统图搜索算法
2026-08-02
TIP

该文章的性质更多的是个人的知识复盘,更好的方便回顾,可能细节与文章连贯性不会很完善

来源是Shakey the robot,全球首款可以自动拆解任务并执行的Robot,内核是SRI 开发的 STRIPS 规划器(Stanford Research Institute Problem Solver),其中,STRIPS规划器所使用的核心的算法便是A*算法


A*搜索算法#

概念#

A*搜索算法,又称启发式搜索,是图遍历以及路径规划的基础方法中较为核心的一种

该算法的核心是通过代价函数 f(n)=g(n)+h(n) 综合考虑“已经走过的代价”和“预计到目标的代价”,优先扩展最有希望的节点,从而高效找到最短路径。

  • g(n)为实际代价:从起点到当前节点已经消耗的路径成本,比如时间,步数,距离等等

  • h(n)为启发函数:从当前节点到目标节点,预计消耗的成本 , 在网格地图中,常常使用曼哈顿距离h(n)=xnxg+ynygh(n)=∣x_{n}​−x_{g}​∣+∣y_{n}​−y_{g}​| , 而在允许斜走的时候,便常用欧氏距离h(n)=(xnxg)2+(ynyg)2h(n)=\sqrt{(x_{n}​−x_{g}​)2+(y_{n}​−y_{g}​)2}

  • 在每一步,程序会计算所有候选节点的f(n),选择最小f(n)对应的节点进行行动,相较于广度优先算法,该算法不再盲目地按照距离层次进行搜索,而是利用启发函数 h(n) 引导搜索方向,使搜索过程更加趋向目标节点,因此能够在保证最优路径的前提下,大幅减少无效节点的扩展,提高搜索效率。

算法代码实现#

from queue import PriorityQueue
def heuristic(a, b):
"""
曼哈顿距离 heuristic
适用于四方向网格
"""
(x1, y1) = a
(x2, y2) = b
return abs(x1 - x2) + abs(y1 - y2)
def a_star_search(graph, start, goal):
"""
A* 搜索
graph:
需要提供:
- neighbors(node)
- cost(from_node, to_node)
start:
起点
goal:
终点
"""
frontier = PriorityQueue()
frontier.put(start, 0)
came_from = {}
cost_so_far = {}
came_from[start] = None
cost_so_far[start] = 0
while not frontier.empty():
current = frontier.get()
if current == goal:
break
for next_node in graph.neighbors(current):
new_cost = (
cost_so_far[current]
+ graph.cost(current, next_node)
)
if (
next_node not in cost_so_far
or new_cost < cost_so_far[next_node]
):
cost_so_far[next_node] = new_cost
priority = (
new_cost
+ heuristic(next_node, goal)
)
frontier.put(next_node, priority)
came_from[next_node] = current
return came_from, cost_so_far

bilibili教程#

Q&A#

预估函数,我们该如何选择#

随着每一步的行动,我们上述的代价函数中 g(n),也就是实际代价会均匀的增加 而h(n),也就是预计到目标的代价,在理想的预估函数估计下,应该是逐渐减少(最佳是增长量与减少量抵消,代价维持不变,也就是传统二维平面三点共线的情况),减小量<=增加量,偶尔在遇到障碍物的情况下h(x)也可能增加.用公式表达,就是h(x) ≤ d(x, y) + h(y) ,即h(x)-h(y)代表的预估值的减少量,可以为负,要小于实际代价的增加量d(x,y),这样就能保证f(x)始终是保持一个单调增长的态势,更便于优化,因此,我们通常选择能满足该公式的预估函数,上述文章使用的曼哈顿距离以及欧氏距离都满足这一点


dijkstra算法#

概念#

Dijkstra(迪杰斯特拉)算法是一种用于求解**单源最短路径问题(Single Source Shortest Path)**的经典算法。 即给定一个节点,Dijkstra算法可以计算这个点到图中其他所有节点的最短距离

讲解演示图

每次选距离a最近的点,然后更新

step1#

d(a-b) = 2 , d(a-c) = 5 取min,也就是d(a-b),接下来以b为出发点

step2#

d(b-c) = 1 , d(b-d) = 3 此时d(a-c)更新为2+1=3,d(a-d)更新为5,取min,也就是d(a-c),接下来以c为出发点

step3#

d(c-d) = 3 , d(c-e) = 4 ,d(c-f) = 1此时d(a-d)不更新(d(a-c-d)>d(a-b-d)),保持5不变,d(a-e) = d(a-c) + d(c-e) = 7 , d(a-f) = 4 选d(a-f)

step4#

f无合适到达点,空置,此时已经确定的是{a,b,c,d} d(a-d) = 5 , d(a-e) = 7 选d(a-d)

step5#

d(d-e) = 1,d(d-f) = 4 更新d(a-e) d(a-f)

最终输出d(a-{x}) , x 包含于 b-f

TIP

有点类似于广度优先算法

算法代码实现#

def dijkstra(graph, start):
"""
Dijkstra 最短路径算法
参数:
graph: 邻接表
{
节点: [(邻居, 权重), ...]
}
start: 起点
返回:
dist: 从 start 到所有节点的最短距离
prev: 最短路径前驱节点
"""
# 初始化距离
dist = {node: float('inf') for node in graph}
dist[start] = 0
# 记录路径
prev = {node: None for node in graph}
# 优先队列:(当前距离, 当前节点)
heap = [(0, start)]
while heap:
current_dist, u = heapq.heappop(heap)
# 如果取出的不是最新距离,跳过
if current_dist > dist[u]:
continue
# 遍历邻居
for v, weight in graph[u]:
new_dist = current_dist + weight
# 松弛操作
if new_dist < dist[v]:
dist[v] = new_dist
prev[v] = u
# 加入优先队列
heapq.heappush(heap, (new_dist, v))
return dist, prev

bilibili教程#

Q&A#

广度优先算法#

概念#

广度优先算法(Breadth-First Search,简称 BFS)是一种用于遍历图、寻找最短路径的算法。它的核心思想是

像水波一样一层一层向外扩散,先访问离起点近的节点,再访问更远的节点。 第一个时间步能访问到哪些节点,第二个时间步…以此类推 由于这里很好理解,就不过多说明,有需要的参考外链,点击前往

算法代码实现#

from collections import deque
def bfs(start):
queue = deque([start])
visited = set([start])
while queue:
node = queue.popleft()
print(node)
for neighbor in graph[node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
bfs("A")

深度优先算法DFS#

概念#

深度优先搜索(Depth-First Search,简称 DFS)是一种用于遍历图、搜索路径以及解决组合优化问题的经典算法。

它的核心思想是:

沿着一条路径不断向更深层节点探索,直到无法继续前进时,再回退(Backtracking)到上一个节点,尝试其他分支。

与广度优先算法 BFS 不同,DFS 不会优先探索距离起点较近的所有节点,而是优先探索当前路径上的深层节点。

算法代码实现#

def dfs(graph, start, visited=None):
"""
深度优先搜索 DFS
graph: 邻接表
start: 起始节点
visited: 已访问节点集合
"""
if visited is None:
visited = set()
# 标记当前节点
visited.add(start)
print(start, end=" ")
# 遍历邻接节点
for neighbor in graph[start]:
if neighbor not in visited:
dfs(graph, neighbor, visited)
return visited
# 测试图
graph = {
"A": ["B", "C"],
"B": ["D", "E"],
"C": ["F"],
"D": [],
"E": ["F"],
"F": []
}
dfs(graph, "A")
NOTE

也就是先遍历A第一个临近节点B,然后再去遍历B的第一个临近节点D,D没有临近节点,再去遍历B的临近节点E 然后依次是F , C ,该算法同样会遍历所有情况,只是优先去探索的深度,适合去验证路线的连通性

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

四大传统图搜索算法
https://mohuaye.cn/posts/traditional-graph-search-algorithms/
作者
番茄可可
发布于
2026-08-02
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录