我的A *算法实现需要一些帮助。 当我运行算法时,它确实找到了目标,但路径肯定不是最短的:-P
这是我的代码,请帮我发现错误! 我认为可能是重建路径是我的问题,但我不确定。
public class Pathfinder {
public List<Node> aStar(Node start, Node goal, WeightedGraph graph) {
Node x, y;
int tentative_g_score;
boolean tentative_is_better;
FScoreComparator comparator = new FScoreComparator();
List<Node> closedset = new ArrayList<Node>();
Queue<Node> openset = new PriorityQueue<Node>(10, comparator);
openset.add(start);
start.g_score = 0;
start.h_score = heuristic_cost_estimate(start, goal);
start.f_score = start.h_score;
while (!openset.isEmpty()) {
x = openset.peek();
if (x == goal) {
return reconstruct_path(goal);
}
x = openset.remove();
closedset.add(x);
for (Edge e : graph.adj(x)) {
if (e.v == x) {
y = e.w;
} else {
y = e.v;
}
if (closedset.contains(y) || y.illegal) {
continue;
}
tentative_g_score = x.g_score + e.weight;
if (!openset.contains(y)) {
openset.add(y);
tentative_is_better = true;
} else if (tentative_g_score < y.g_score) {
tentative_is_better = true;
} else {
tentative_is_better = false;
}
if (tentative_is_better) {
y.g_score = tentative_g_score;
y.h_score = heuristic_cost_estimate(y, goal);
y.f_score = y.g_score + y.h_score;
y.parent = x;
}
}
}
return null;
}
private int heuristic_cost_estimate(Node start, Node goal) {
return Math.abs(start.x - goal.x) + Math.abs(start.y - goal.y);
}
private List<Node> reconstruct_path(Node current_node) {
List<Node> result = new ArrayList<Node>();
while (current_node != null) {
result.add(current_node);
current_node = current_node.parent;
}
return result;
}
private class FScoreComparator implements Comparator<Node> {
public int compare(Node n1, Node n2) {
if (n1.f_score < n2.f_score) {
return 1;
} else if (n1.f_score > n2.f_score) {
return -1;
} else {
return 0;
}
}
}
}
感谢所有人的所有好答案! 我的A *算法现在非常适合你们! : - )
这是我的第一篇文章,这个论坛非常棒!
答案 0 :(得分:7)
插入后,您正在更改PriorityQueue
中元素的优先级。这不受支持,因为优先级队列不知道对象已更改。您可以做的是在对象发生变化时删除并重新添加该对象。
优先级在行中更改:y.f_score = y.g_score + y.h_score;
。将y
添加到优先级队列后会发生此行。请注意,在计算成本后简单地将行openset.add(y);
移动到这一点是不够的,因为在上一次迭代中可能添加了y
。
您的代码中还不清楚您使用的启发式是admissible。如果不是,它也会导致您获得次优路径。
最后,效果说明:contains
和ArrayList
上的PriorityQueue
方法需要线性时间才能运行,这会使您的实施的运行时间不是最佳的。您可以通过向节点添加布尔属性来指示它们是否在闭合/打开集中,或者使用设置数据结构来改进这一点。
答案 1 :(得分:3)
更改优先级时,优先级队列不会更新项目的位置。 因此堆属性不成立。 更改的优先级会影响其他项的添加/删除,但它不会修复堆属性。
因此,您没有从开放中获得最佳项目 - &gt;你找不到最短路径。
您可以: 1)编写自己的堆并将索引保存到其中 2)将另一个对象添加到PQ中并将旧对象标记为无效(您必须代替节点将某个对象设置为有效标志并将节点引用到队列中)。
2)性能更差,我建议反对它,但有些导航软件使用这种方法(或者至少在几年前使用它)。
编辑:最佳做法是,将不可变(或至少包含优先级可知的部分)对象插入PriorityQueue