我的路径查找方法有两个对象,包含id,name,x / y坐标和存储在Array List中的路径。路径数据是它可以直接连接的每个对象的id。目标是递归调用我的方法,直到它使用最短距离找到它的目标,当它到达结束时它返回true。
问题: 如果到达的节点的距离比当前节点路径中的其他节点短,那么它将导致无限循环在两个节点之间来回弹跳。我已经在这个问题上挣扎了好几个小时,可能会过度思考它。任何建议或建议将不胜感激!
算法:
while (!pathfound) {
current = findPath(current, end);
}
public static Place findPath(Place curPlace, Place endPlace) {
ArrayList<Integer> path = curPlace.path;
int id;
double lastdist = 999;
double distance;
Place bestPlace = null;
for (int i = 0; i < path.size(); i++) {
id = curPlace.path.get(i);
distance = distance(getPlace(id), curPlace)
+ distance(getPlace(id), endPlace);
if (distance < lastdist) {
bestPlace = getPlace(id);
}
lastdist = distance;
}
if (result.length() == 0) {
result += bestPlace.name;
} else {
result += ", " + bestPlace.name;
}
System.out.println("CURCITY: " + bestPlace.id);
System.out.println(result);
System.out.println(lastdist);
if (bestPlace == endPlace) {
pathfound = true;
}
return bestPlace;
}
您可以忽略结果,它可以跟上传递的节点。如果您想了解其他任何细节,请询问。
答案 0 :(得分:3)
如果可以修改Place
,则可以添加布尔“被访问”标志。在运行算法之前将它们全部重置为false;当你访问时设置为true而当你离开时设置为false(不要忘记在离开递归的途中取消设置它们 - 如果你正确地执行此操作,你甚至可以避免在启动之前显式重置标志)。跳过标志为真的节点。
更近视的选项是将最后访问过的Place
作为参数传递给函数,并跳过该函数。这不会阻止更大的循环,但可能完全适合您的情况,并且最简单的实现。
以上两者都是O(1),开销最小。如果您无法修改Place
,则可以存储Set
个访问过的位置(在递归的方式中将其从集合中删除),并跳过已在该集合中的位置。根据您的性能要求,如果您使用HashSet
,则需要提供适当的散列函数。
沿着这些方向,以更多内存为代价,如果您的ID号是唯一的并且覆盖了合理大小的有限范围,则由ID号索引的boolean[]
是此处集合的常量时间替代(它是本质上是“访问”标志选项,标志存储在外部。)
答案 1 :(得分:2)
使用递归方法查找路径算法可能非常棘手,因为您总是需要某种全局信息来评估,两种路径中的哪一种更适合。在遵循单一路径的同时,您永远无法确定它是否正确。即使您始终遵循最近的节点,也不一定是正确的路径。这被称为best-first search策略,尽管它不是最好的,它可以使用,但你必须确保尝试其他路径,因为你不能通过简单地坚持下去最近的节点。
如果要进行路径查找算法,则需要跟踪已经详尽探索的所有节点,因此永远不需要再次访问。这可以通过将访问节点的列表存储在某种结构中来明确地完成,或者您可以更聪明地执行此操作并通过良好的策略设计来强制执行此操作以选择要访问的新节点。
换句话说,如果您跟踪要访问的节点以及到每个节点的距离(priority queue),并且您始终确保访问最近的尚未访问的节点,那么您将永远不会重新访问相同的节点,而不必明确强制执行,例如在A* algorithm或Dijkstra中。