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