A*算法保姆级教程:从原理到Python实现,5分钟搞定最短路径问题

张开发
2026/4/6 20:58:49 15 分钟阅读

分享文章

A*算法保姆级教程:从原理到Python实现,5分钟搞定最短路径问题
A*算法保姆级教程从原理到Python实现5分钟搞定最短路径问题当你打开手机地图寻找最短路线时当仓库机器人自动规划最优搬运路径时背后都藏着一个聪明的算法——A*A-Star。作为路径规划领域的明星算法它既不像DFS那样盲目也不像Dijkstra那样保守而是像一位经验丰富的向导总能快速找到最优路线。今天我们就用Python从零开始揭开它的神秘面纱。1. 为什么A*算法如此高效想象你在陌生的商场里找洗手间。盲目搜索BFS会像无头苍蝇一样逛遍每个角落保守策略Dijkstra则坚持走最短累积距离可能绕远路。而聪明人会查看导览图估算直线距离启发式优先探索靠近目标的方向代价评估动态调整路线开放列表管理这就是A*的核心思想——启发式搜索。它通过以下公式评估每个节点的优先级f(n) g(n) h(n)其中g(n)从起点到当前节点的实际代价h(n)当前节点到终点的预估代价启发函数关键点启发函数h(n)必须满足可采纳性不高估实际代价常用曼哈顿距离或欧几里得距离。2. 算法实现四步走2.1 构建地图模型我们用一个二维矩阵表示地图其中0可通行路径1障碍物grid [ [0, 0, 0, 0, 1, 0], [1, 1, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0] ]2.2 定义节点类每个节点需要记录坐标位置g值实际代价h值预估代价父节点用于回溯路径class Node: def __init__(self, parentNone, positionNone): self.parent parent self.position position self.g 0 self.h 0 self.f 0 def __eq__(self, other): return self.position other.position2.3 核心算法实现def astar(grid, start, end): # 初始化开放列表和关闭列表 open_list [] closed_list [] # 创建起始节点和终点节点 start_node Node(None, start) end_node Node(None, end) open_list.append(start_node) while open_list: # 获取当前节点f值最小 current_node min(open_list, keylambda x: x.f) # 到达终点时回溯路径 if current_node end_node: path [] while current_node: path.append(current_node.position) current_node current_node.parent return path[::-1] # 反转路径 # 移动到关闭列表 open_list.remove(current_node) closed_list.append(current_node) # 遍历相邻节点 for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0)]: # 四方向移动 node_position ( current_node.position[0] new_position[0], current_node.position[1] new_position[1] ) # 检查边界 if (node_position[0] len(grid) or node_position[0] 0 or node_position[1] len(grid[0]) or node_position[1] 0): continue # 检查障碍物 if grid[node_position[0]][node_position[1]] 1: continue # 创建新节点 new_node Node(current_node, node_position) # 如果在关闭列表中则跳过 if new_node in closed_list: continue # 计算g、h、f值 new_node.g current_node.g 1 new_node.h abs(end_node.position[0] - new_node.position[0]) \ abs(end_node.position[1] - new_node.position[1]) # 曼哈顿距离 new_node.f new_node.g new_node.h # 如果新节点已在开放列表且g值更大则跳过 if any(open_node for open_node in open_list if open_node new_node and open_node.g new_node.g): continue open_list.append(new_node) return None # 未找到路径2.4 可视化路径使用matplotlib展示算法效果import matplotlib.pyplot as plt import numpy as np def visualize(grid, path): grid_array np.array(grid) plt.figure(figsize(8,6)) plt.imshow(grid_array, cmapbinary) if path: x_coords [x[1] for x in path] y_coords [y[0] for y in path] plt.plot(x_coords, y_coords, r-, linewidth2) plt.grid(whichmajor, colorgray, linestyle-, linewidth1) plt.xticks(range(len(grid[0]))) plt.yticks(range(len(grid))) plt.show()3. 算法优化技巧3.1 启发函数选择对比启发函数类型计算公式适用场景是否可采纳曼哈顿距离h x1-x2欧几里得距离h √((x1-x2)² (y1-y2)²)任意方向移动是切比雪夫距离h max(x1-x2,3.2 开放列表的优先队列优化使用堆结构提升最小f值节点查找效率import heapq # 修改开放列表为优先队列 open_list [] heapq.heappush(open_list, (start_node.f, start_node)) while open_list: current_node heapq.heappop(open_list)[1] # ...其余逻辑不变...3.3 动态加权启发式在复杂环境中平衡速度与最优性w 1.5 # 权重系数 new_node.h w * (abs(end_node.position[0] - new_node.position[0]) abs(end_node.position[1] - new_node.position[1]))4. 实战机器人路径规划假设我们有一个20x20的仓库地图机器人需要从(0,0)移动到(19,19)中间有随机障碍物# 生成随机地图 import random random.seed(42) grid [[0 if random.random() 0.2 else 1 for _ in range(20)] for _ in range(20)] grid[0][0] 0 # 确保起点畅通 grid[19][19] 0 # 确保终点畅通 # 执行A*算法 path astar(grid, (0,0), (19,19)) visualize(grid, path)常见问题解决方案路径抖动增加移动方向八方向使路径更平滑局部最优引入重规划机制当遇到新障碍时重新计算性能瓶颈使用跳点搜索(JPS)等优化变种在真实项目中我习惯先用曼哈顿距离快速验证算法逻辑再根据实际移动方式调整启发函数。对于动态环境通常需要每200ms重新计算一次路径同时保留部分已探索区域信息以提升效率。

更多文章