新闻中心
A 算法实现常见陷阱:解决节点探索不足的问题

本文深入探讨了a*寻路算法在实现过程中一个常见的逻辑错误,即因错误地使用起始节点而非当前节点来探索邻居,导致算法过早停止且无法到达目标。文章将详细分析此问题,提供修正后的代码示例,并强调了正确迭代与邻居探索对于确保a*算法有效运行的关键性。
A* 算法核心原理回顾
A 算法是一种广泛应用于路径规划和图搜索领域的启发式搜索算法,它通过结合 Dijkstra 算法的精确性和最佳优先搜索的效率来找到从起点到终点的最短路径。A 算法的核心在于其评估函数 f(n) = g(n) + h(n),其中:
- g(n) 是从起点到节点 n 的实际代价。
- h(n) 是从节点 n 到终点的预估启发式代价(启发函数)。
- f(n) 是从起点经过节点 n 到终点的总预估代价。
算法维护两个集合:openSet(待探索节点)和 closedSet(已探索节点)。openSet 通常是一个优先队列,根据 f(n) 值从小到大排序,每次取出 f(n) 最小的节点进行扩展。
常见错误分析:邻居节点探索逻辑
在 A* 算法的实现中,一个常见的错误是未能正确地在每次迭代中更新当前节点,并基于这个“当前节点”来探索其邻居。原始代码中存在的问题正是如此:在主循环内部,每次从 openSet 中取出 current 节点后,本应探索 current 节点的邻居,但却错误地始终使用 start_node 来调用 find_neighbors 函数。
# 原始代码片段中的错误
while not openSet.isEmpty():
current = openSet.dequeue()
# ... 其他逻辑 ...
# 错误之处:始终使用 start_node 探索邻居
for neighbour in find_neighbors(start_node, graph):
# ... 后续处理 ...这种错误会导致算法在第一次迭代时正确地探索了起始节点的邻居,并将它们添加到 openSet 中。然而,在随后的迭代中,即使从 openSet 中取出了一个新的 current 节点,算法仍然会再次探索 start_node 的邻居,而不是 current 节点的邻居。这意味着算法永远无法离开起始节点的直接邻域,从而无法向目标节点前进,最终在探索完起始节点的邻居后便停止,未能找到目标路径。
Playground AI
AI图片生成和修图
99
查看详情
正确实现与代码示例
要修正这个错误,只需将 find_neighbors 函数的第一个参数从 st
art_node 改为 current 即可。这样,在每次循环中,算法都会根据当前正在处理的节点来正确地发现并评估其周围的邻居。
以下是修正后的 A* 算法代码:
import heapq
# 假设 PriorityQueue 是一个简单的基于 heapq 的实现
class PriorityQueue:
def __init__(self):
self._queue = []
self._entry_finder = {} # 映射条目到其在队列中的位置 (用于高效更新)
self._counter = 0 # 唯一计数器,用于处理优先级相同的情况
def enequeue(self, priority, item): # 注意:原始代码中使用的是 enequeue,此处保留
if item in self._entry_finder:
self.remove(item)
count = self._counter
self._counter += 1
entry = [priority, count, item]
self._entry_finder[item] = entry
heapq.heappush(self._queue, entry)
def dequeue(self):
while self._queue:
priority, count, item = heapq.heappop(self._queue)
if item is not None:
del self._entry_finder[item]
return item
raise KeyError('dequeue from an empty priority queue')
def remove(self, item):
entry = self._entry_finder.pop(item)
entry[-1] = None # 标记为删除,不从堆中实际移除,惰性删除
def isEmpty(self):
return not self._entry_finder
def contains(self, item):
return item in self._entry_finder
# 启发函数(例如:曼哈顿距离)
def heuristic(node_a, node_b):
x1, y1 = node_a
x2, y2 = node_b
return abs(x1 - x2) + abs(y1 - y2)
# 查找邻居节点函数
def find_neighbors(node, graph):
x, y = node
neighbors = []
# 假设 graph 是一个包含所有有效节点坐标的集合或字典
# 这里的 graph 应该包含所有可通行的坐标点
potential_neighbors = [
(x + 1, y), # 右
(x - 1, y), # 左
(x, y + 1), # 下
(x, y - 1) # 上
]
for neighbor_coord in potential_neighbors:
if neighbor_coord in graph: # 检查邻居是否在图中(可通行区域)
neighbors.append(neighbor_coord)
return neighbors
# 路径回溯函数
def RetracePath(cameFrom, end_node):
path = []
current = end_node
while current in cameFrom:
path.append(current)
current = cameFrom[current]
path.append(current) # 添加起始节点
return path[::-1] # 反转路径以从起点到终点
def AStar(start_node, end_node, graph):
openSet = PriorityQueue()
openSet.enequeue(0, start_node) # 初始fCost为0,因为是起点
infinity = float("inf")
gCost = {} # 从起点到当前节点的实际代价
fCost = {} # 从起点经过当前节点到终点的总预估代价
cameFrom = {} # 记录路径,每个节点的前一个节点
# 初始化所有节点的gCost和fCost为无穷大
for node in graph: # 遍历图中所有节点进行初始化
gCost[node] = infinity
fCost[node] = infinity
gCost[start_node] = 0
fCost[start_node] = heuristic(start_node, end_node)
while not openSet.isEmpty():
current = openSet.dequeue() # 获取fCost最小的节点
if current == end_node:
print(f"Goal reached! Path: {RetracePath(cameFrom, end_node)}")
return RetracePath(cameFrom, end_node)
# 核心修正:探索 current 节点的邻居,而不是 start_node 的邻居
for neighbour in find_neighbors(current, graph):
# 假设每一步的代价为1
tempGCost = gCost[current] + 1
if tempGCost < gCost[neighbour]:
cameFrom[neighbour] = current
gCost[neighbour] = tempGCost
fCost[neighbour] = tempGCost + heuristic(neighbour, end_node)
if not openSet.contains(neighbour):
openSet.enequeue(fCost[neighbour], neighbour)
# 调试输出,可以根据需要保留或删除
# print(f"Came from: {cameFrom}\nCurrent: {current}")
print("No path found.")
return False # 如果openSet为空,表示没有找到路径
find_neighbors 函数说明: 这个函数负责根据给定的 node 坐标,查找其上下左右四个方向的邻居。它会检查这些潜在邻居是否在 graph(通常表示可通行区域的集合或字典)中,以确保只返回有效的、可到达的邻居。这个函数的实现是正确的,关键在于 A* 主算法如何调用它。
注意事项与优化建议
- PriorityQueue 实现: 示例中的 PriorityQueue 是一个基于 heapq 的简单实现,它支持更新节点优先级(通过标记旧条目为 None 并插入新条目)。在实际应用中,如果需要频繁更新节点的优先级,确保优先队列能够高效处理这一操作至关重要。Python 的 heapq 模块本身不支持直接更新,通常需要像示例中那样结合字典进行惰性删除。
- graph 数据结构: 在 find_neighbors 函数中,graph 被假定为一个可以快速查询某个坐标是否存在的集合或字典。例如,如果地图是一个二维网格,graph 可以是一个包含所有可通行坐标元组的 set,或者是一个二维数组,其中每个元素表示该位置是否可通行。
- 启发函数 heuristic: 启发函数 h(n) 的选择对 A* 算法的性能至关重要。它必须是“可接受的”(admissible),即永远不会高估从当前节点到目标节点的实际代价。对于网格地图,曼哈顿距离(如示例所示)或欧几里得距离是常见的选择。
- 路径回溯 RetracePath: 当目标节点被找到时,通过 cameFrom 字典从目标节点反向追溯到起始节点,即可重建最短路径。
- 边界条件和无路径情况: 确保算法能够正确处理起始节点即为目标节点、或者无法找到任何路径到达目标节点的情况。当 openSet 变为空且未找到目标时,应返回无路径结果。
总结
A 算法的正确实现依赖于对其核心逻辑的精确把握,特别是关于节点扩展和邻居探索的部分。本文通过分析一个常见的错误——即在迭代中错误地探索起始节点的邻居而非当前节点的邻居——并提供了修正方案,强调了在 A 算法中,每次从优先队列中取出 current 节点后,都必须以 current 节点为中心来探索其邻居,才能确保算法沿着正确的路径逐步逼近目标。理解并避免此类常见陷阱是成功实现高效 A* 路径规划算法的关键。
以上就是A 算法实现常见陷阱:解决节点探索不足的问题的详细内容,更多请关注其它相关文章!
# 而非
# 楚雄营销推广公司招聘
# 企业推广网站哪个好用
# 站长之家查询不到seo数据
# 对网站优化注意什么
# 黑龙江影楼网站建设
# SEO与主机
# 企业营销推广方案外包
# 保险网站建设的目标
# 社区店应该怎么推广营销
# 宣城企业营销推广方式
# 转换为
# 最短
# python
# 正确地
# 数据结构
# 迭代
# 是从
# 曼哈顿
# 点到
# 是一个
# cos
# ai
# app
# go
# node
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
中兴BladeV30怎样用测距估书架层高_iPhone中兴BladeV30测距估书架层高【家装参考】
如何使 Jest 模拟函数默认抛出错误以提高测试效率
怎样把文件彻底粉碎无法恢复_Windows下安全删除敏感数据【隐私保护】
在哪找SublimeJ远程工具_SFTP插件配置教程
深入理解rpy2中的类型转换:优化Python对象到R矩阵的映射
J*a TimerTask文件监控:HashMap状态管理与常见陷阱规避指南
html5 app怎么运行环境_配html5 app运行环境【教程】
怎样使用“本地安全策略”提升Windows安全性_Secpol.msc配置指南【高手】
字由网在线版登录地址 字由网网页版安全入口
如何在复杂的电商平台中优雅地管理共享资源并确保正确重定向,使用spryker-shop/resource-share-page模块助你一臂之力
HTML5原生日期选择器与jQuery UI:实现日期选择器的联动与程序化控制
生成rdflib自定义SPARQL函数:参数匹配与实践指南
解决Python单元测试中Mock异常方法调用计数为零的问题
理解J*aScript Promise的微任务队列与执行顺序
在J*a中如何捕获IndexOutOfBoundsException_索引越界异常防护方法说明
包子漫画官方网站阅读入口-包子漫画在线漫画官网直达链接
处理嵌套交互式控件:前端可访问性指南
知乎APP怎么管理已购盐选内容_知乎APP盐选内容购买记录与查看方法
NetBeans Ant项目:自动化将资源文件复制到dist目录的教程
整合Supabase认证与Django模型:跨模式迁移的解决方案
Django通过AJAX异步上传图片并保存至模型的完整指南
uc浏览器网页版极速入口 uc网页浏览器网页版流畅体验
Tabulator表格中精确实现日期时间排序的指南
漫蛙漫画登录站点 漫蛙2正版漫画快速访问
J*aScript中在Map循环中检测并处理空数组元素
win11如何加载ICC颜色配置文件 Win11校色文件安装与显示器色彩管理【指南】
俄罗斯Yandex免登录入口_Yandex搜索引擎官网一键直达
JUnit5/Mockito:优雅测试内部依赖与异常处理的实践
2025年云电脑操作系统体验 | 无需本地硬件,随时随地使用高性能PC
Word2013如何插入视频和音频媒体_Word2013媒体插入的多媒体支持
漫蛙2网页版漫画入口 漫蛙漫画在线官方登录
怎么去除衣服上的口红印_生活小妙招教你用酒精轻松擦除
微信商城在哪里打开【步骤】
抖音隐秘迷城小游戏入口_ 抖音冒险解谜小游戏秒玩
厨房不锈钢水槽发黑生锈怎么处理_水槽用可乐+锡纸2分钟抛亮如新
LINQ to XML为何解析失败? 深入理解C# XDocument的异常处理
J*a里如何实现订单支付与库存同步功能_支付库存同步项目开发方法说明
漫蛙漫画网页端入口 漫蛙2官方正版漫画站点
Node.js中HTML按钮与J*aScript函数交互的正确姿势
树莓派传感器触发:通过Twilio API发送WhatsApp消息教程
sublime怎么进行远程开发编辑_配置rsub/rmate实现sublime编辑服务器文件
汽水音乐网页版使用入口_汽水音乐电脑版播放指南
学习通在线学习平台 学习通网页版直接进入课程中心
抖音小游戏合成大西瓜免费秒玩入口链接 抖音小游戏热门合集秒玩网站
消息称三星明年 2 月正式发布 HBM4,与 SK 海力士同台竞技
必由学官网入口 必由学教师登录入口
谷歌google账号注册详细步骤 谷歌账号注册官方教程
sublime如何配置Python开发环境_将sublime打造成轻量级Python IDE
Win11怎么查看电脑配置_Win11硬件配置检测工具使用
电脑屏幕颜色不舒服怎么办_Windows夜间模式与色彩校准教程【护眼技巧】


2025-12-05
浏览次数:次
返回列表