php语言中A-star寻路算法的运用

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

猜你喜欢

转载自blog.csdn.net/cxk_mz/article/details/80503177