我曾经问过A *的数据结构。我现在解决了这个问题。但还有另一个问题。我的A *很慢,没有按照我的预期工作。这意味着 我用维基百科伪代码(德语和英语)用Java实现了源代码。下图中的图表是我用于测试目的的图表。例如,算法从节点1开始到目的地节点8。将使用曼哈顿距离使用节点旁边的方形制动器中的坐标来计算启发函数。封闭列表从起始节点1(前身)到3(1)-6(3)-2(1)-4(1)-3(2)-2(3)-4(3)-8(6)构建)。我认为A *直接从1到8,因为它是最短的路径。但它从6跳回到节点2,因为2的f值是列表中的最低值。这是正确的吗?在示例中,我看到它在之后访问节点之后从未跳转到任何其他节点。我有一个图表,它从两个方向与其他节点连接。因此,我改变了源代码中的if条件,以证明反向方式是否在相应的列表中。否则它将以无限循环结束。 问题是什么,为什么它从节点6跳回到节点2?我是否必须删除我的公开列表中的节点? 。
public ArrayList<NodeD> executeAstar(ArrayList<Arclistentry> data, NodeD start, NodeD dest)
{
openlist = new PriorityQueue<NodeD>(1,comp);
closedlist.clear();
openlist.offer(start);
start.setg(0);
start.seth( manhattendistance(start, dest));
start.setf(start.getg()+start.geth());
while(!openlist.isEmpty())
{
NodeD currentnode = openlist.poll();
if(currentnode.getnodenumber() == dest.getpredessor())
{
closedlist.add(currentnode);
return closedlist;
}
closedlist.add(currentnode);
for(int i=0; i< data.size(); i++)
{
if(data.get(i).getstart()==currentnode.getnodenumber())
{
NodeD successor = new NodeD(data.get(i).getnode(),data.get(i).getstart(), data.get(i).getcoorddest());
NodeD reversesuccessor = new NodeD(data.get(i).getstart(),data.get(i).getnode(),data.get(i).getcoordstart());
float tentative_g = currentnode.getg()+data.get(i).getcost();
if((contains(successor, closedlist)||contains(reversesuccessor, closedlist))&&(tentative_g >=successor.getg()))
{
continue;
}
if(!(contains(successor, openlist))|| (tentative_g < successor.getg()))
{
successor.setpredessor(currentnode.getnodenumber());
successor.setg(tentative_g);
successor.seth(manhattendistance(successor, dest));
successor.setf(successor.getg()+manhattendistance(successor, dest));
if(!contains(successor, openlist))
{
openlist.offer(successor);
}
}
}
}
}
ArrayList<NodeD> ret = null;
return ret;
}
答案 0 :(得分:2)
A *中的启发式必须是admissible - 也就是说,它绝不能过高估计在两个节点之间移动的成本。
在您的示例中,[2,4]
和[4,2]
之间的费用为3,但Manhatten距离为4.因此,它是不允许的,并且不适合您作为启发式。
我是否必须删除公开列表中的节点?
呃,是的,否则你的while
循环永远不会完成。甚至在pseudocode