You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

A*算法无法生成完整单一路径 求代码正确性验证

A*路径规划算法问题排查与修复

我实现了A*路径规划算法,但生成的目标路径不符合预期。节点评估看似正常,但最终路径列表中存在G值相同的节点,无法确定算法是否正常工作。

原实现代码

A*算法实现

startNode = getTile(new Point(3,6));
targetNode = getTile(new Point(1,4));
ArrayList<Node> closedList;
void AStar() {
    closedList = new ArrayList<>();
    ArrayList<Node> openList = new ArrayList<>();
    startNode.g = 0;
    startNode.h = heuristic(startNode,targetNode);
    startNode.f = startNode.g+startNode.h;
    Log.d("COST",startNode.h+"");
    cost = startNode.h;
    openList.add(startNode);
    while (!openList.isEmpty()) {

        //Find the node with the lowest f value
        int lowestFcost = openList.get(0).f;
        Node processNode = openList.get(0);
        for(int i = 1;i<openList.size();i++){
            if(openList.get(i).f < lowestFcost){
                lowestFcost = openList.get(i).f;
                processNode = openList.get(i);
            }
        }


        if (processNode.equals(targetNode)) {
            path(processNode);
            return;
        }
        openList.remove(processNode);
        closedList.add(processNode);

        for (Node n:nextNodes(processNode)) {
            //check if n is in the closed list
            if(closedList.contains(n)){
                // skip forloop once
                Log.d("SKIPLOOP","true");
            }else {


                if (!openList.contains(n)) {
                    openList.add(n);

                } else {
                    for (Node n2 : openList) {
                        if (n2.equals(n)) {


                            if (processNode.g<n.g) {


                                //better g score
                                n2.g = heuristic(processNode,startNode);
                                n2.h = heuristic(processNode,targetNode);
                                n2.f = n2.g+n2.h;
                                n2.parent = processNode;
                                Log.d("NODE","XY:"+n2.getPosition().toString()+" Gcost:"+n2.g+" Fcost:"+n2.f+" Hcost:"+n2.h);
                                //n2.view.setBackgroundColor(getResources().getColor(R.color.primary_light,null));


                            }
                    }


                    }


                }

            }
        }

    }
new ToastEasy(getApplicationContext(),"Not Possible to reach Target");
}


private Node getTile(Point tilePosition){
    Node tile = null;
    for (Node t:MapTileList) {
        if(tilePosition.equals(t.getPosition())){
            tile = t;
            break;
        }
    }
    return tile;
}


private ArrayList<Node> nextNodes(Node node){

    ArrayList<Node>NextNodeList = new ArrayList<>();
    if(node.getPosition().x-1 >= 0 ){
        //Add a left Node
        Node n = getTile(new Point(node.getPosition().x-1,node.getPosition().y));
        //n.parent = node;
        n.g = heuristic(n,startNode);
        n.h = heuristic(n,targetNode);
        n.f = n.g+n.h;
        n.view.setBackgroundColor(getResources().getColor(R.color.green,null));
        NextNodeList.add(n); //Left Node
    }
    if(node.getPosition().y-1 >= 0){
        //Add a top Node
        Node n = getTile(new Point(node.getPosition().x,node.getPosition().y-1));

        //n.parent = node;
        n.g = heuristic(n,startNode);
        n.h = heuristic(n,targetNode);
        n.f = n.g+n.h;
        n.view.setBackgroundColor(getResources().getColor(R.color.green,null));
        NextNodeList.add(n); //Top Node
    }
    if(node.getPosition().x+1 <= cols ){
        //Add a Right Node
        Node n = getTile(new Point(node.getPosition().x+1,node.getPosition().y));

        //n.parent = node;
        n.g = heuristic(n,startNode);
        n.h = heuristic(n,targetNode);
        n.f = n.g+n.h;
        n.view.setBackgroundColor(getResources().getColor(R.color.green,null));
        NextNodeList.add(n);
    }
    if(node.getPosition().y+1 <= rows) {
        //Add a Bottom Node
        Node n = getTile(new Point(node.getPosition().x, node.getPosition().y + 1));

        //n.parent = node;
        n.g = heuristic(n,startNode);
        n.h = heuristic(n,targetNode);
        n.f = n.g+n.h;
        n.view.setBackgroundColor(getResources().getColor(R.color.green,null));
        NextNodeList.add(n);

    }
    return NextNodeList;
}
void path(Node node){
    int lastCost = 0;
    ArrayList<Node>Path = new ArrayList<>();
    for (Node node1 : closedList) {
       if(node1.parent != null){

           node1.view.setBackgroundColor(getResources().getColor(R.color.black,null));
           Path.add(node1);

           //Log.d("PATHLIST",Path.get(i).getPosition()+" Gcost"+Path.get(i).g+" Hcost"+Path.get(i).h+" Fcost"+Path.get(i).f);
       }

    }

    Log.d("PATHLIST",Path.size()+"");

}

private int heuristic(Node node1, Node node2){


    return Math.abs((node1.getPosition().x-node2.getPosition().x))
            +
            Math.abs((node1.getPosition().y-node2.getPosition().y));

}

Node类实现

import android.graphics.Point;
import android.widget.ImageButton;
import android.widget.TextView;

public class Node {
    Point position;
    public int f,g,h;
    public Node parent;
    public ImageButton view;
    public Node(Point position, int f, int g, int h, Node parent, ImageButton view) {
        this.position = position;
        this.f = f;
        this.g = g;
        this.h = h;
        this.parent = parent;
        this.view = view;
    }
    public Point getPosition(){

        return this.position;


    }
}

关键问题与修复方案

1. G值计算逻辑错误

G值代表从起点到当前节点的实际移动成本,不是当前节点到起点的曼哈顿距离。四方向移动每步成本为1,所以正确的G值计算应为父节点G值 + 1。

  • 修复nextNodes方法中的G值计算:
// 替换原n.g = heuristic(n,startNode);
n.g = node.g + 1;
  • 修复节点更新时的G值计算:
// 替换原n2.g = heuristic(processNode,startNode);
n2.g = processNode.g + 1;

2. H值更新错误

H值是当前节点到终点的曼哈顿距离,不是父节点到终点的距离。节点更新时应保持H值为当前节点的启发值:

// 替换原n2.h = heuristic(processNode,targetNode);
n2.h = heuristic(n2, targetNode);

3. 路径回溯逻辑错误

原path方法遍历closedList收集节点的方式完全错误,正确的路径应从目标节点开始,沿着parent回溯到起点:

void path(Node targetNode) {
    ArrayList<Node> path = new ArrayList<>();
    Node current = targetNode;
    while (current != null) {
        path.add(current);
        current.view.setBackgroundColor(getResources().getColor(R.color.black,null));
        current = current.parent;
    }
    // 反转路径得到从起点到终点的顺序
    Collections.reverse(path);
    Log.d("PATHLIST", "路径长度:" + path.size());
    for (Node node : path) {
        Log.d("PATHNODE", "XY:" + node.getPosition().toString() + " Gcost:" + node.g);
    }
}

4. 缺少equals和hashCode方法

Node类未重写equals和hashCode,导致contains方法无法正确判断节点是否为同一位置的节点。添加以下代码到Node类:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Node node = (Node) o;
    return position.equals(node.position);
}

@Override
public int hashCode() {
    return position.hashCode();
}

5. 节点更新时的判断逻辑优化

原代码中遍历openList查找节点效率低,且判断条件processNode.g < n.g应改为(processNode.g + 1) < n2.g,因为新的G值是父节点G+1:

// 替换原判断部分
if (!openList.contains(n)) {
    n.parent = processNode;
    n.g = processNode.g + 1;
    n.h = heuristic(n, targetNode);
    n.f = n.g + n.h;
    openList.add(n);
} else {
    int newG = processNode.g + 1;
    if (newG < n.g) {
        n.parent = processNode;
        n.g = newG;
        n.f = n.g + n.h;
        Log.d("NODE","XY:"+n.getPosition().toString()+" Gcost:"+n.g+" Fcost:"+n.f+" Hcost:"+n.h);
    }
}

修复后说明

修复以上问题后,G值会正确反映从起点到节点的实际步数,路径回溯会得到从起点到终点的正确路径,不会再出现G值异常的情况。

内容的提问来源于stack exchange,提问作者Brett Ezra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 13:05:57