手撸一个A*+二叉堆优化(一)

尽量会讲的通俗易懂

寻路有很多种,A*是一种启发式搜索:启发式搜索就是在状态空间中的搜索对每一 个搜索的位置进行评估,得到最好的位置,再从这个位置 进行搜索直到目标。这样可以省略大量无谓的搜索路径, 提到了效率。 在启发式搜索中,对位置的估价是十分重要的。采用了不 同的估价可以有不同的效果。

估价函数:从当前节点移动到目标节点的预估费用;这个 估计就是启发式的。在寻路问题和迷宫问题中,我们通常用曼哈顿(manhattan)估价函数预估费用。

俗话说的好用空间换时间,A*算法在理论上是时间最优的,但是也有 缺点:它的空间增长是指数级别的。(优化:二叉堆)

开始搜索需要三个list

开启列表openset:待检查方格的集合列表,寻找周围可以达到的点,加入到此表中, 并保存中心点为父节点.

关闭列表closeset:列表中保存不需要再次检查的方格

路径列表path:父节点组成

路径评分

G=与起始点的距离

H=与目标点的距离

F的值是G和H的和。F,G和H的评分被写在每 个方格里。

左上角是G,右上角是H

中间是F

这个价格是自己定的,比如这里平移是10,那么斜角就是根号2*10=14

从A点到B点开始搜索,A点周围8个点加入开启列表,这8个点的父节点是A,从开启列表寻找F最小的点作为下一个点,如果F相同就寻找H最小的,也就是离目标点最近的点。这里右上角42明显最小。

现在中心点移动到42,A点加入关闭列表,重新计算42周围格子的G(跳过障碍物和在关闭列表中的点),因为初始点变化了G就要变化,H是不会变的,如果重新计算的G小于之前的G,替换估价值,将这个G变化的格子的父节点替换成当前中心的,这里42周围两个48原本G是10,14+10>10,所以不替换估价,不替换父节点也就是还是A,将新增加的两个格子48和62加入开启列表,这两个新格子的父节点则为42这个中心点,继续寻找下一个点。

42周围3个48,用之前的规则,选择H=24的点,重新计算周围的格子,同样没出现G比之前小的格子,添加两个新格子(父节点是48)到开启列表后继续寻找下一个点。也就是右下角的48

新中心成为48后发现,62的G变小的了,也就是10+10<28,所以替换62为54,将这个格子的父节点从之前的替换为当前的中心点,新格子加入开启列表,然后一直找一直找,直到结束

结束条件有两种,一种是中心点是B点的时候,也就是找到了B,

另一种就是所有地图跑遍了还没有找到。

如果找的了B点就可以根据父节点反推出这条最短路径了

伪代码如下

开启集合openset

关闭集合closeset

路径集合path

添加起始点到开始集合中

循环如下步骤:

当前点=开启集合中最小F_Cost的点

将当前点移出开启集合中 Remove

将当前点添加到关闭集合中 Add

如果当前点是目标点,结束查询

遍历当前点的每个相邻点

如果相邻点不能访问(障碍物)或者相邻点在关闭集合中,跳过此相邻点

如果新路径到相邻点的距离更短(newG<oldG)

重新设置F_Cost 重新设置其父节点为当前点

如果相邻点不在开启集合中 (!openSet.Contains(node))添加相邻点到开启集合中

如果结束了查询,开始将目标点的父节点的父节点的父节点以此加入path集合,最后反转集合。


代码的实现——下(you)回(kong)分(zai)解(xie)

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dijkstra算法是一种用于解决单源最短路径问题的经典算法,而二叉堆是一种常用的数据结构,用于实现Dijkstra算法中的优先队列。下面是Dijkstra算法结合二叉堆的Python代码实现: ```python import heapq def dijkstra(graph, start): # 初始化距离字典,用于记录起点到各个节点的最短距离 distances = {node: float('inf') for node in graph} distances[start] = 0 # 初始化优先队列,用于存储待处理的节点 queue = [(0, start)] while queue: # 弹出当前最小距离的节点 current_distance, current_node = heapq.heappop(queue) # 如果当前节点已经被处理过,则跳过 if current_distance > distances[current_node]: continue # 遍历当前节点的邻居节点 for neighbor, weight in graph[current_node].items(): distance = current_distance + weight # 如果通过当前节点到达邻居节点的距离更短,则更新最短距离并加入优先队列 if distance < distances[neighbor]: distances[neighbor] = distance heapq.heappush(queue, (distance, neighbor)) return distances ``` 上述代码中,`graph`表示图的邻接表表示,`start`表示起点。`distances`字典用于记录起点到各个节点的最短距离,初始时将所有节点的距离设为无穷大,起点的距离设为0。`queue`优先队列用于存储待处理的节点,初始时将起点加入队列。 在算法的主循环中,每次从优先队列中弹出当前最小距离的节点,然后遍历其邻居节点。如果通过当前节点到达邻居节点的距离更短,则更新最短距离并将邻居节点加入优先队列。 最后,返回`distances`字典,即起点到各个节点的最短距离。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值