A-star
算法具体实现如下所示
名词解释:
open
数组:存放与预操作的节点
close
数组:存放已经遍历过的节点
pNode
:当前结点的上一节点的信息(父节点)
G
值:从起点,沿着已产生的路径,移动到当前操作的节点需要的的距离
H
值:从当前操作的节点移动到目的地距离评估,此系统中采用了欧式距离来进行
评估,即H = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2))
F
值:F=G+H
tempNode:
临时存放当前操作的节点
nextNodes
数组:
临时存放当前节点的相邻节点
nextNode:
相邻节点
nodeEnd
:终点
nodeStart
:起点
nodes
数组:
存放最优路径涉及节点
算法实现步骤:
(1
)设置open
数组和close
数组,其元素对象包含pNode
,F
值,G
值,H
值
(2
)取起点,设置pNode
,F
值,G
值,H
值,父节点信息为NULL
,G
值为0
。
(3
)将起点存入open
数组
(4
)进行循环操作,循环停止条件为nodeEnd
加入了$close
数组
(5
)取open
中F
值最小的元素,如果F
值相同则取G
值较小的。记为tempNode
(6
)将tempNode
加入到close
数组中,从open
数组中删除tempNode
(7
)寻找tempNode
的可到达的相邻节点存于nextNodes
数组中
(8
)遍历nextNodes
数组记每个元素为nextNode
,并对其进行操作
(9
)设置pNode
,F
值,G
值,H
值
(10
)检测nextNode
是否在close
数组中
(11
)在close
数组
不操作
(12
)不在close
数组
检测是否在open
数组中
(13
)在open
数组
检测open
中的此元素的G
值是否大于nextNode
的G
值
(14
)如果小于
则参照nextNode
更新open
中的此元素的父节点信息,F
值,G
值,H
值
(15
)如果大于
则不操作
(16
)如果不在open
数组
则将nextNode
插入到open
数组
(17
)返回步骤4
进行循环
(18
)结束循环后遍历close
数组根据pNode
信息取出有用的元素存入nodes
中
(19
)得到的nodes
数组即为最优路径所包含的节点
注释:如果进行步骤14
的操作,则可能在close
数组中产生垃圾数据,步骤18
目的是删除close
中的没用的节点信息。
以下为php的代码,其中$roads存储着图结构中任意两两节点间的连通的路径,$nodeStart 起点 ,$nodeEnd终点
public function calculateRoute($roads,$nodeStart,$nodeEnd){ $open = []; $close = []; //新建$node,将初始值存入,同时为其填充H,G,F的值 $tempNode['node'] = $nodeStart['node']; $tempNode['p_node'] = null; $tempNode['coord_x'] = $nodeStart['coord_x']; $tempNode['coord_y'] = $nodeStart['coord_y']; $H_Y = $nodeEnd['coord_y']-$tempNode['coord_y']; $H_X = $nodeEnd['coord_x']-$tempNode['coord_x']; $tempNode['H'] = sqrt($H_Y*$H_Y+$H_X*$H_X); $tempNode['G'] = 0; $tempNode['F'] = $tempNode['H'] + $tempNode['G']; //将$node加入到open中 array_push($open,$tempNode); //如果$nodeEnd存入了$close中,则停止操作 for(;!$this->detectionArrayB($close,$nodeEnd);){ //获取open中最小值存在$element中 $element1 = $this->getOpenElement($open); //删除$open中的最小值 unset($open[$element1['key']]); //重新整理$open $open = array_values($open); //$open中的最小值插入到$close中 array_push($close,$element1['node']); //对$tempNode相临的节点进行操作 foreach ($roads as $key=>$value){ //如果roads中node_start等于$element['node']['node']代表node_end为临近节点 if($roads[$key]['node_start']==$element1['node']['node']){ //从roads中获取下一节点的元素信息 $nextNode['node'] = $roads[$key]['node_end']; $nextNode['p_node'] = $roads[$key]['node_start']; $nextNode['coord_x'] = $roads[$key]['coord_end_x']; $nextNode['coord_y'] = $roads[$key]['coord_end_y']; $H_Y = $nodeEnd['coord_y']-$nextNode['coord_y']; $H_X = $nodeEnd['coord_x']-$nextNode['coord_x']; $nextNode['H'] = sqrt($H_Y*$H_Y+$H_X*$H_X); $nextNode['G'] = $element1['G'] + $roads[$key]['length']; $nextNode['F'] = $nextNode['H'] + $nextNode['G']; //nextNode不在$close中进行以下操作 if(!$this->detectionArrayB($close,$nextNode)){ //检测$open中是否存在$nextNode $element2 = $this->detectionArrayA($open,$nextNode); //如果$tempDetectionElement不为空则代表nextNode在$open中 if(count($element2)!=0){ //如果open中nextNode的G值过大则进行替换 if($nextNode['G']<$element2['node']['G']){ $open[$element2['key']] = $nextNode; } } else array_push($open,$nextNode); } } } } //将$close中有用的节点存入$nodes中 $close = array_reverse($close); $nodes[0] = $close[0]; $finalNode = $nodes[0]; for($i=1;$i<count($close);$i++){ if($close[$i]['node']==$finalNode['p_node']){ $finalNode = $close[$i]; array_push($nodes,$finalNode); } } return $nodes; }