A星进一步优化,让二叉堆更快,更猛。as3版

二叉堆优化提高了A星一大步,但是想要更快,更猛,还不能停步。这两天整理自己的A星,啃了些网上搜的一些大神源码,今天整理下思路分享下。

A星原理和二叉优化在天地会文章很多,这里就不多说了,要读此文先,提前是对A星有一定了解。(本文思路源于别人代码,不是我原创,呵呵)

 

优化大多是用空间换时间,把过程的计算量放到初始存入内存。下面直接进入正题吧。

一、障碍邻点的预计算。

判断周围格子是否有障碍还有计算格子的cost价值,如果在每次寻路的时候才去算就太浪费了,因为每次寻路的时候每个格子相邻的障碍是不会变的,价值cost也不变,我们大可以把这块计算抽出放到初始地图的时候计算。步骤如下:

1.给节点添加邻节点数组nodeLinks,和邻节点价值组costLinks。(也可建一个linkNode对象,对象里面有节点和价值两属性,反正两数组是个映对关系),保证nodeLinks[i]的价值是costLinks[i]

2.地图初始好的时候遍历每个格子,计算出其周围的所有非障碍的格子,并加入节点邻数组中存起。计算每个邻节点的价值,映对存入节点价值组。

3.寻路的时候判断节点四周有哪些格子直接从当前计算的节点的nodeLinks属性取即可,不需要再计算。

预计算可节省很多性能,不过缺点是初始的时候很慢。 

 

二、Array数组优化

Array的indexOf和shift方法是很吃性能的,很多人的A星在while里面有这两个东西,这是那几百毫秒慢下的原因。怀疑的同学可以自己写个1万次的大循环调用这两个方法看看。要判断节点是否在开户组里面,普通人的做法是用indexOf,其实这个方式可以换成以下处理

1.给节点添加isOpen:Boolean属性

2.每次push节点到打开数组的里面设节点的isOpen为true

3.节点移出打开列表时,将节点的isOpen属性设为false

4.判断节点是否在开启列表时只需要判断isOpen即可

判断关闭同理,另外还有会用上indexOf的地方是二叉堆里面,干掉方式略。

将关闭组添加到通过父节点添加到返回路径时,很多人会用shift,把节点一个个添到path数组里面,这也是个慢的因素。可以换成push方式,push不会改变索引,所以效率很高。将关闭节点组数据通过push加入路径后,再调用reverse把数组倒置,结果跟用shift一样,不过用时可大不一样。

 

三、打开关闭标记,换掉不用重置

用isOpen来替代indexOf大大提升了一步性能,可是每次寻路完之后会有个问题,那就是要把节点重置,就是把所有打开和关闭列表里面的节点的isOpen,isClose设false。呵呵,虽然这个重置吃的性能相当小,不过本着追求精神,我又找出了更变态的方式。步骤如下

1.每次A星计算设一唯一自增标记markIndex,每计算一次寻路,这个整型属性+1

2.把节点里面的isOpen和isClose布尔属性改成openMark,closeMark整型属性。

3.加入列表时把openmark设为本次计算的自动标记markIndex,移出列表设为-1(或随便一个不等于markIndex的数)

4.判断是否在打开列表中只需判断if(openMark==markIndex)即可

5.某次寻路计算完之后markIndex+1

因为自增标记每次计算都不一样,所以节点的openMark不需要重置,下次也能继续用。这个方式带来的性能提升很微小不多,不追求那几十毫秒的大可无视。

 

四、减少while里面get/set/function

get/set的性能其实很高,不过在项目中,大量的格子一经过while方法就是数万次的运算,虽然每次性能相差很少,但量一大起来效率就明显了。不信的人可以写个大循环在里面用getter和public属性的方式对比一下,性能相差三四倍。如果节点的f,g,h,x,y这些属性用了接口get/set,那个运算毫秒相差就很明显了。function 是代码设计不可省的东西,这一步优化只适合在A星的while中用,正常项目中可省不得。

 

五、位运算,再提一提微小的性能

在二叉堆中的除以2,num/2==num*0.5==num >> 1,这三个种计算方式最快的明显是第三种,虽然可读性差些,不过效率还是有点提升滴。另外num*2 == num<<1;也可提升些性能

 

目前能想到的提速度方法就这样,先开篇日记记录一下,以后找到新的再补。源码还没整理好,暂时先这么上了

转载于:https://www.cnblogs.com/pelephone/archive/2012/09/27/astar-fastest.html

你可能感兴趣的:(A星进一步优化,让二叉堆更快,更猛。as3版)