文章目录

在学习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. oracle 字段自增 两段代码搞定

    (这几天做了个小小课程设计时用的是oracle数据库,第一次用,发现oracle和我们以前用的sql server .mysql是有如此多不同的地方,下面是遇到的问题之一和解决方法,和大家分享下) 用 ...

  2. LeetCode——Consecutive Numbers

    Description: Write a SQL query to find all numbers that appear at least three times consecutively. + ...

  3. LeetCode——Number of 1 Bits

    //求一个整数的二进制串中1的个数 public int hammingWeight(int n) { String b_str = Integer.toBinaryString(n); int b_ ...

  4. flash 逐字,逐行歌词实现,添加伪3D效果

    项目结构: 效果如图: 项目为公司项目,下载人员禁止用于商业项目中. 项目开发工具:FlashDevelop 点击下载

  5. 2.void 0 与 不可靠的undefined

    在 ES5 之前,全局的 undefined 也是可以被修改的,而在 ES5 中,该标识符被设计为了只读标识符, 假如你现在的浏览器不是太老,你可以在控制台中输入以下语句测试一下: undefined ...

  6. WCF(五) 深入理解绑定

    适用于本机WCF-WCF交互性能最佳的绑定: 允许跨主机,但只能用于部署同一台主机上,不能访问命名管道 netNamePipeBinding总结 一 WCF与SOA SOA是一种通过为所有软件提供服务 ...

  7. ExecutorService的四种线程池

    转自:https://www.cnblogs.com/zhaoyan001/p/7049627.html 1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new ...

  8. 无向连通图求割点(tarjan算法去掉改割点剩下的联通分量数目)

    poj2117 Electricity Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3603   Accepted: 12 ...

  9. spring cloud多个消费端重复定义feign client问题

    spring cloud消费端调用服务提供者,有两种方式rest+ribbon和Feign,Feign是一个声明式的伪Http客户端更为简单易用,所以我们项目选用Feign作为服务通讯方式 项目有6个 ...

  10. Yii2 高级模板不使用Apache配置目录,将前后台入口移到根目录

    刚刚入手Yii2高级模板不久,部署项目时,得部署2个应用,个人感觉很繁琐,就将前后台入口文件全部拿到项目根目录.但是一看,完了,出错了!找教程找不到,还是自己解决吧 为了以后好升级,不改变Yii2核心 ...