Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java *实现总是返回相同的值_Java_Algorithm_Shortest Path_A Star - Fatal编程技术网

Java *实现总是返回相同的值

Java *实现总是返回相同的值,java,algorithm,shortest-path,a-star,Java,Algorithm,Shortest Path,A Star,我似乎不是疯了,就是错误地实现了A*算法: 下面是我的代码,似乎无论我输入什么值,它都将返回360。我是否遗漏了一些关键信息?在任何人问“是”之前,这与我收到的机器学习作业有关 公共A级明星{ 公共搜索节点(int-cost,int-xCoordinate,int-yccoordinate){ 这个。成本=成本; this.xCoordinate=xCoordinate; this.yCoordinate=yCoordinate; } 公共int getCost(){ 退货成本; } } 下面是

我似乎不是疯了,就是错误地实现了A*算法:

下面是我的代码,似乎无论我输入什么值,它都将返回360。我是否遗漏了一些关键信息?在任何人问“是”之前,这与我收到的机器学习作业有关

公共A级明星{

公共搜索节点(int-cost,int-xCoordinate,int-yccoordinate){
这个。成本=成本;
this.xCoordinate=xCoordinate;
this.yCoordinate=yCoordinate;
}
公共int getCost(){ 退货成本; }

}

下面是我的代码,似乎没有 无论我输入什么值,它都将 始终返回360

我的第一个猜测是,每个节点都有一个固定的启发式成本。那么360可能来自哪里呢

final SearchNode START_NODE = new SearchNode(0,115,655);
final SearchNode END_NODE = new SearchNode(0,380,560);
假设您使用的是曼哈顿距离启发法,(380-115)+(655-560)=265+95=360


由于格式的原因,代码有点难读。但我的猜测是,您计算了开始节点的h值,然后将其用于此后的每个节点。记住,h(x)我假设图是一个规则的矩形网格,其中有障碍节点,所有解都不应该通过。此外,我假设从一个节点到一个邻居节点的旅行是1。我还意识到曼哈顿距离被用作启发

考虑到这些,我恐怕你的是一个错误的实施

首先,您应该使用迭代方法,而不是递归方法。考虑到图形的大小,如果它是一个正确的实现,您肯定会得到Stackoverflows

其次,关于价值、价值、价值和/或成本的概念似乎存在问题。我觉得有必要对这些术语作一个非正式的描述

A*使用的简单公式是F=G+H,其中

G是当前计算的从起始节点到当前节点的旅行成本。因此,对于起始节点,Gvalue应该是0,从startNode可以到达的任何节点的G值都应该是1(我的假设是这样的,从一个节点移动到一个相邻节点)。我想在这里强调“当前”一词,因为节点的Gvalue在算法运行期间可能会改变

H是成本的启发式部分,表示从当前节点到结束节点的成本。与G部分不同,节点的H值根本不会改变(我这里有一个疑问,可能有这样的启发吗?你的没有,让我们继续),它应该只计算一次。您的实现似乎使用曼哈顿距离作为启发式,这无疑是此类图的最佳启发式。但是要小心,我的朋友,这里似乎也有一个小问题:差异的绝对值应该分开,然后求和

F是这些值的总和,表示从当前节点传递解决方案的可能成本(给定图形和启发式,任何计算出的F值都应该等于或小于实际成本,这很好)

有了这些,我将使用如下SearchNode:

public class SearchNode {
    private int xCoordinate;
    private int yCoordinate;
    private double gScore;
    private double hScore;

    public double getfScore() {
        return gScore + hScore;
    }

    public double getgScore() {
        return gScore;
    }

    public void setgScore(int gScore) {
        this.gScore = gScore;
    }


    public SearchNode(int xCoordinate,int yCoordinate, double gScore, SearchNode endNode) {
        this.gScore=gScore;
        this.hScore = //Manhattan distance from this node to end node
        this.xCoordinate =xCoordinate;
        this.yCoordinate = yCoordinate;
    }

   public int getxCoordinate() {
       return xCoordinate;
   }

   public int getyCoordinate() {
       return yCoordinate;
   }
}
然后,该算法可以实现如下:

private ArrayList<SearchNode> closedNodes = new ArrayList<SearchNode>();
private ArrayList<SearchNode> openNodes = new ArrayList<SearchNode>();
//create the start and end nodes
SearchNode end = new SearchNode(380, 560, -1, null);
SearchNode start = new SearchNode(115,655, 0, end);


// add start node to the openSet

openNodes.Add(start);

while(openNodes.Count > 0) // while there still is a node to test
{
    // I am afraid there is another severe problem here.
    // OpenSet should be PriorityQueue like collection, not a regular Collection.
    // I suggest you to take a look at a Minimum BinaryHeap implementation. It has a logN complexity
    // of insertion and deletion and Constant Complexity access.

   // take the Node with the smallest FValue from the openSet. (With BinHeap constant time!)
    SearchNode current = openNodes.GetSmallestFvaluedNode(); // this should both retrieve and remove the node fromt he openset.

    // if it is the endNode, then we are node. The FValue (or the Gvalue as well since h value is zero here) is equal to the cost.
    if (current.EqualTo(end)) // not reference equality, you should check the x,y values
{
    return current.getfScore();
}

   //check the neighbourNodes, they may have been created in a previous iteration and already present in the OpenNodes collection. If it is the case, their G values should be compared with the currently calculated ones.
 // dont forget to check the limit values, we probably do not need nodes with negative or greater than the grid size coordinate values, I am not writing it
 // also here is the right place to check for the blocking nodes with a simple for loop I am not writing it either

  double neighbourGValue = current.getgScore() + 1;
 if (openNodes.Contains(current.getXCoordinate(), current.getYCoordinate() + 1))
  {
     // then compare the gValue of it with the current calculated value.
     SearchNode neighbour = openNodess.getNode(current.getXCoordinate(), current.getYCoordinate() + 1);
     if(neighbour.getgScore() > neighbourGValue)
        neighbour.setgScore(neighbourGValue);
  }
  else if(!closedNodes.Contains(current.getXCoordinate(), current.getYCoordinate()))
  {
      // create and add a fresh Node
     SearchNode n = new SearchNode(current.getXCoordinate(), current.getYCoordinate() + 1, neighbourGValue, endNode);
     openNodes.Add(n);
  }
  // do the same for the other sides : [x+1,y - x-1,y - x, y-1]

  // lastly add the currentNode to the CloseNodes.
  closedNodes.Add(current);
}

// if the loop is terminated without finding a result, then there is no way from the given start node to the end node.
 return -1;
即使将开集实现为最小二进制堆,也没有简单的方法检查非最小f值节点。我现在记不起细节了,但我记得用logN复杂度实现了这个。此外,我的实现是在一次调用中访问和更改该节点的g值(如果有必要的话),这样您就不用再花时间检索它了。无论g值是否更改,若存在具有给定坐标的节点,它都返回true,所以不会生成新节点

当我写完所有这些时,我意识到了最后一件事。您说过,对于给定的任何输入,您的实现都在计算相同的结果。如果你提到的输入是障碍节点,那么大多数情况下,无论是什么实现,它都会发现相同的距离,因为它在寻找尽可能短的距离。在下图中,我试图解释这一点


这很可能就是我把事情搞砸的地方,谢谢,我会调查一下,很抱歉我的回答太详细了,我的朋友,我很感谢你花了这么多时间。我将采纳这些建议,并相应地加以应用。不要重复使用此框架:
final SearchNode START_NODE = new SearchNode(0,115,655);
final SearchNode END_NODE = new SearchNode(0,380,560);
public class SearchNode {
    private int xCoordinate;
    private int yCoordinate;
    private double gScore;
    private double hScore;

    public double getfScore() {
        return gScore + hScore;
    }

    public double getgScore() {
        return gScore;
    }

    public void setgScore(int gScore) {
        this.gScore = gScore;
    }


    public SearchNode(int xCoordinate,int yCoordinate, double gScore, SearchNode endNode) {
        this.gScore=gScore;
        this.hScore = //Manhattan distance from this node to end node
        this.xCoordinate =xCoordinate;
        this.yCoordinate = yCoordinate;
    }

   public int getxCoordinate() {
       return xCoordinate;
   }

   public int getyCoordinate() {
       return yCoordinate;
   }
}
private ArrayList<SearchNode> closedNodes = new ArrayList<SearchNode>();
private ArrayList<SearchNode> openNodes = new ArrayList<SearchNode>();
//create the start and end nodes
SearchNode end = new SearchNode(380, 560, -1, null);
SearchNode start = new SearchNode(115,655, 0, end);


// add start node to the openSet

openNodes.Add(start);

while(openNodes.Count > 0) // while there still is a node to test
{
    // I am afraid there is another severe problem here.
    // OpenSet should be PriorityQueue like collection, not a regular Collection.
    // I suggest you to take a look at a Minimum BinaryHeap implementation. It has a logN complexity
    // of insertion and deletion and Constant Complexity access.

   // take the Node with the smallest FValue from the openSet. (With BinHeap constant time!)
    SearchNode current = openNodes.GetSmallestFvaluedNode(); // this should both retrieve and remove the node fromt he openset.

    // if it is the endNode, then we are node. The FValue (or the Gvalue as well since h value is zero here) is equal to the cost.
    if (current.EqualTo(end)) // not reference equality, you should check the x,y values
{
    return current.getfScore();
}

   //check the neighbourNodes, they may have been created in a previous iteration and already present in the OpenNodes collection. If it is the case, their G values should be compared with the currently calculated ones.
 // dont forget to check the limit values, we probably do not need nodes with negative or greater than the grid size coordinate values, I am not writing it
 // also here is the right place to check for the blocking nodes with a simple for loop I am not writing it either

  double neighbourGValue = current.getgScore() + 1;
 if (openNodes.Contains(current.getXCoordinate(), current.getYCoordinate() + 1))
  {
     // then compare the gValue of it with the current calculated value.
     SearchNode neighbour = openNodess.getNode(current.getXCoordinate(), current.getYCoordinate() + 1);
     if(neighbour.getgScore() > neighbourGValue)
        neighbour.setgScore(neighbourGValue);
  }
  else if(!closedNodes.Contains(current.getXCoordinate(), current.getYCoordinate()))
  {
      // create and add a fresh Node
     SearchNode n = new SearchNode(current.getXCoordinate(), current.getYCoordinate() + 1, neighbourGValue, endNode);
     openNodes.Add(n);
  }
  // do the same for the other sides : [x+1,y - x-1,y - x, y-1]

  // lastly add the currentNode to the CloseNodes.
  closedNodes.Add(current);
}

// if the loop is terminated without finding a result, then there is no way from the given start node to the end node.
 return -1;
if (openNodes.Contains(current.getXCoordinate(), current.getYCoordinate() + 1))