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; }