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

本文详细介绍了A*寻路算法的具体实现过程,包括算法的基本概念、关键步骤及PHP实现代码。通过设置open和close数组来跟踪节点状态,利用F值(G值+H值)确定最佳路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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数组,其元素对象包含pNodeF值,G值,H
2)取起点,设置pNodeF值,G值,H值,父节点信息为NULLG值为0
3)将起点存入open数组
4)进行循环操作,循环停止条件为nodeEnd加入了$close数组
5)取openF值最小的元素,如果F值相同则取G值较小的。记为tempNode
6)将tempNode加入到close数组中,从open数组中删除tempNode
7)寻找tempNode的可到达的相邻节点存于nextNodes数组中
8)遍历nextNodes数组记每个元素为nextNode,并对其进行操作
9)设置pNodeF值,G值,H
10)检测nextNode是否在close数组中
11)在close数组 不操作
12)不在close数组 检测是否在open数组中
13)在open数组 检测open中的此元素的G值是否大于nextNodeG
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值