文章目录

在学习A*算法之前,很好奇的是A*为什么叫做A*。在知乎上找到一个回答,大致意思是说,在A*算法之前有一种基于启发式探索的方法来提高Dijkstra算法的速度,这个算法叫做A1。后来的改进算法被称为A*。*这个符号是从统计文献中借鉴来的,用来表示相对一个旧有标准的最优估计。

启发式探索是利用问题拥有的启发信息来引导搜索,达到减少探索范围,降低问题复杂度的目的。

A*寻路算法就是启发式探索的一个典型实践,在寻路的过程中,给每个节点绑定了一个估计值(即启发式),在对节点的遍历过程中是采取估计值优先原则,估计值更优的节点会被优先遍历。所以估计函数的定义十分重要,显著影响算法效率。

A*算法描述

简化搜索区域

将待搜索的区域简化成一个个小方格,最终找到的路径就是一些小方格的组合。当然是可以划分成任意形状,甚至是精确到每一个像素点,这完全取决于你的游戏的需求。一般情况下划分成方格就可以满足我们的需求,同时也便于计算。
如下图区域,被简化成6*6的小方格。其中绿色表示起点,红色表示终点,黑色表示路障,不能通行。

概述算法步骤

先描述A*算法的大致过程:

  1. 将初始节点放入到open列表中。
  2. 判读open列表。如果为空,则搜索失败。如果open列表中存在目标节点,则搜索成功。
  3. 从open列表中取出F值最小的节点作为当前节点,并将其加入到close列表中。
  4. 计算当前节点的相邻的所有可到达节点,生成一组子节点。对于每一个子节点:
    • 如果该节点在close列表中,则丢弃它
    • 如果该节点在open列表中,则检查其通过当前节点计算得到的F值是否更小,如果更小则更新其F值,并将其父节点设置为当前节点。
    • 如果该节点不在open列表中,则将其加入到open列表,并计算F值,设置其父节点为当前节点。
  5. 转到2步骤

进一步解释

初始节点,目标节点,分别表示路径的起点和终点,相当于上图的绿色节点和红色节点
F值,就是前面提到的启发式,每个节点都会被绑定一个F值
F值是一个估计值,用F(n) = G(n) + H(n) 表示,其中G(n)表示由起点到节点n的固定消耗,H(n)表示节点n到终点的估计消耗。H(n)的计算方式有很多种,比如曼哈顿H(n) = x + y,或者欧几里得式H(n) = sqrt(x^2 + y^2)。本例中采用曼哈顿式。
F(n)就表示由起点经过n节点到达终点的总消耗
为了便于描述,本文在每个方格的左下角标注数字表示G(n),右下角数字表示H(n),左上方数字表示F(n)。具体如何计算请看下面的一个例子

具体寻路过程

接下来,我们严格按照A*算法找出从绿色节点到红色节点的最佳路径
首先将绿色节点加入到open列表中
接着判断open列表不为空(有起始节点),红色节点不在open列表中
然后从open列表中取出F值最小的节点,此时,open列表中只有绿色节点,所以将绿色节点取出,作为当前节点,并将其加入到close列表中
计算绿色节点的相邻节点(暂不考虑斜方向移动),如下图所示的所有灰色节点,并计算它们的F值。这些子节点既没有在open列表中,也没有在close列表中,所以都加入到open列表中,并设置它们的父节点为绿色节点

F值计算方式
以绿色节点右边的灰色节点为例
G(n) = 1,从绿色节点移动到该节点,都只需要消耗1步
H(n) = 3,其移动到红色节点需要消耗横向2步,竖向一步,所以共消耗3步(曼哈顿式)
F(n) = 4 = G(n) + H(n)

试着算一下其他灰色节点的F值吧,看看与图上标注的是否一致

继续选择open列表中F值最小的节点,此时最小节点有两个,都为4。这种情况下选取哪一个都是一样的,不会影响搜索算法的效率。因为启发式相同。这个例子中按照右下左上的顺序选取(这样可以少画几张图(T▽T))。先选择绿色节点右边的节点为当前节点,并将其加入close列表。其相邻4个节点中,有1个是黑色节点不可达,绿色节点已经被加入close列表,还剩下上下两个相邻节点,分别计算其F值,并设置他们的父节点为黄色节点。

此时open列表中F值最小为4,继续选取下方节点,计算其相邻节点。其右侧是黑色节点,上方1号节点在close列表。下方节点是新扩展的。主要来看下左侧节点,它已经在open列表中了。根据算法我们要重新计算它的F值,按经过2号节点计算H(n) = 3,G(n)不变,所以F(n) = 6相比于原值反而变大了,所以什么也不做。(后面的步骤中重新计算F值都不会更小,不再赘述)

此时open列表中F值最小仍为4,继续选取

此时open列表中F值最小为6,优先选取下方节点

此时open列表中F值最小为6,优先选取右方节点

此时open列表中F值最小为6,优先选取右方节点

此时open列表中F值最小为6,优先选取右方节点

此时我们发现红色节点已经被添加到open列表中,算法结束。从红色节点开始逆推,其父节点为7号,7号父节点为6号,6号父节点为5号…,最终得到检索路径为:绿色-1-2-5-6-7-红色


模拟需要更新F值的情况

在上面的例子中,所有遇到已经在open列表中的节点重新计算F值都不会更小,无法做更新操作。
所以再举一个例子来演示这种情况。相同的搜索区域,假设竖向或横向移动需要消耗1,这次也支持斜方向移动了,但是斜方向可能都是些山路不好走,移动一次需要消耗4。对应的相邻节点F值如下图所示

同样选择open列表中F值最小的节点,我们优先选择了右方节点,计算其相邻节点。共8个。其中三个是黑色节点,一个绿色节点在close列表中,不考虑。上方两个和下方两个都是已经在open列表中了,要重新计算F值。
先看左上角的相邻节点,通过黄色节点到达改节点,H(n) = 5,G(n)不变,F(n)反而更大了,所以什么也不做。左下角节点同理。
上方居中节点,通过黄色节点计算H(n) = 2, G(n)不变,F(n) = 6 < 8 所以,更新这个节点的F值,并将其父节点修改为黄色节点。下方居中节点同理。


Lua代码实现

写了一套A*算法的Lua实现。主要特点如下:

  • 优化效率,采用了map缓存,避免多次循环遍历

  • 支持配置移动权重

  • 支持配置是否可以斜向移动,斜向时墙角是否可通行

源码请查看:https://github.com/iwiniwin/LuaKit/blob/master/AStar.lua

A*寻路算法详细解读的更多相关文章

  1. Madgwick算法详细解读

    Madgwick算法详细解读 极品巧克力 前言 接上一篇文章<Google Cardboard的九轴融合算法>. Madgwick算法是另外一种九轴融合的方法,广泛应用在旋翼飞行器上,效果 ...

  2. 和textrank4ZH代码一模一样的算法详细解读

    前不久做了有关自动文摘的学习,采用方法是TextRank算法,整理和大家分享. 一. 关于自动文摘 利用计算机将大量的文本进行处理,产生简洁.精炼内容的过程就是文本摘要,人们可通过阅读摘要来把握文本主 ...

  3. 相机IMU融合四部曲(一):D-LG-EKF详细解读

    相机IMU融合四部曲(一):D-LG-EKF详细解读 极品巧克力 前言 前两篇文章<Google Cardbord的九轴融合算法>,<Madgwick算法详细解读>,讨论的都是 ...

  4. 【转载】 A* 寻路算法 (个人认为最详细,最通俗易懂的一个版本)

    原文地址: http://www.cppblog.com/christanxw/archive/2006/04/07/5126.html =============================== ...

  5. MemCache超详细解读

    MemCache是什么 MemCache是一个自由.源码开放.高性能.分布式的分布式内存对象缓存系统,用于动态Web应用以减轻数据库的负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高 ...

  6. A星寻路算法介绍

    你是否在做一款游戏的时候想创造一些怪兽或者游戏主角,让它们移动到特定的位置,避开墙壁和障碍物呢? 如果是的话,请看这篇教程,我们会展示如何使用A星寻路算法来实现它! 在网上已经有很多篇关于A星寻路算法 ...

  7. 用简单直白的方式讲解A星寻路算法原理

    很多游戏特别是rts,rpg类游戏,都需要用到寻路.寻路算法有深度优先搜索(DFS),广度优先搜索(BFS),A星算法等,而A星算法是一种具备启发性策略的算法,效率是几种算法中最高的,因此也成为游戏中 ...

  8. MemCache超详细解读 图

    http://www.cnblogs.com/xrq730/p/4948707.html   MemCache是什么 MemCache是一个自由.源码开放.高性能.分布式的分布式内存对象缓存系统,用于 ...

  9. 关于A*寻路算法的认识

    最近要参加学校的APP比赛,我们组做的是一个3D迷宫的小APP,我负责的是迷宫的生成与寻路. 寻路算法选择的是A*寻路算法,具体参考的是下面的这篇博客. 本文主要是谈谈自己对A*算法的理解,具体细节, ...

随机推荐

  1. js实现表单项的全选、反选以及删除操作

    <html> <head> <title>test</title> <script language="javascript" ...

  2. HTTP/2探索第一篇——概念

    版权声明:本文由张浩然原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/87 来源:腾云阁 https://www.qclou ...

  3. console.log()的兼容性

    在别人那里看到的,兼容IE8-的console.log的实现,以前没想过. if(typeof console == "undefinde"){ this.console = {l ...

  4. DFS判断正环

    hdu1217 Arbitrage Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  5. mysql数据库新插入数据,需要立即获取最新插入的id

    在MySQL中,使用auto_increment类型的id字段作为表的主键.通常的做法,是通过“select max(id) from tablename”的做法,但是显然这种做法需要考虑并发的情况, ...

  6. 使用_Capistrano_进行自动化部署(2)

    之前的一篇文章是为了解决问题而写的,很多东西都没有介绍清楚,这一篇文章就是完整介绍一下 Capistrano,主要的参考来源是 Modern PHP 这本书. Capistrano 是用于自动部署应用 ...

  7. ubuntu16.04下用笔记本摄像头和ROS编译运行ORB_SLAM2的单目AR例程

    要编译ORB_SLAM2的ROS例程首先需要安装ROS,以及在ROS下安装usb_cam驱动并调用,最后搭建ORB_SLAM2. 1.ROS的安装 我的电脑安装的是ubuntu16.04系统,所以我安 ...

  8. Django - 常用配置

    一.logging配置 Django项目常用的logging配置 settings.py LOGGING = { 'version': 1, 'disable_existing_loggers': F ...

  9. (2.1)DDL增强功能-数据类型、同义词、分区表

    1.数据类型 (1)常用数据类型 1.整数类型 int 存储范围是-2,147,483,648到2,147,483,647之间的整数,主键列常设置此类型. (每个数值占用 4字节) smallint ...

  10. 流畅的python 读书笔记 第二章 序列构成的数组 列表推导

    列表推导是构建列表(list)的快捷方式,而生成器表达式则可以用来创建其他任何类型的序列.如果你的代码里并不经常使用它们,那么很可能你错过了许多写出可读性更好且更高效的代码的机会. 2.2.1 列表推 ...