[英]Breadth-first search strategy for searching in map taking too long
使用BFS搜索的程序出现问题。 我给这个方法Node n
,如果它使用方法n.expand
找到通往目标n
方法,它应该给我返回true
。 还有其他一些类可以实现Node
和expand
和isTarget
方法。 如果距离较短,则可以使用,但是如果这些节点之间的距离较长,则大约需要15分钟或更长时间。 谁能帮助我解决这个问题?
public boolean prog(Node n)
{
Queue<Node> FIFO = new LinkedList<Node>();
List<Node> close = new LinkedList<Node>();
FIFO.add(n);
while (true) {
n = FIFO.poll();
if (close.contains(n)) {
} else {
close.add(n);
}
close.add(n);
for (int i = 0; i < n.expand().size(); i++) {
if (!close.contains(n.expand().get(i))) {
FIFO.add(n.expand().get(i));
} else {
}
if (n.expand().get(i).isTarget()) {
return true;
}else{
}
}
}
}
考虑到close
是一个LinkedList
, close.contains
是一项非常昂贵的检查-最坏的情况是它需要遍历整个列表以查找该元素,所以我想这close.contains
很多时间。
如果您熟悉big-O表示法(如果不是,我建议您阅读这篇文章 ), LinkedList.contains
为O(n), HashSet.contains
为O(1), TreeSet.contains
为O(log n) 。
我还建议您将n.expand()
调用移出for循环,而不是将其存储在您使用的临时变量中。 (可能)对n.expand()
每次调用都将导致不得不再次设置相邻节点的集合。
A *搜索算法也可以作为替代BFS的考虑因素。 这涉及估算到目的地的成本(称为“启发式”),使我们能够专注于我们认为与目的地接近的节点。
您可以想到双向BFS 。
将源和目标都视为源,并检查它们是否在某个中间节点相遇。 那应该节省很多时间。
您的代码看起来很奇怪,我已对其进行了一些修复。
public boolean prog(Node n)
{
Queue<Node> FIFO = new LinkedList<Node>();
List<Node> close = new LinkedList<Node>();
FIFO.add(n);
while (!FIFO.empty()) {
n = FIFO.poll();
if( n.isTarget() )
return true;
for (int i = 0; i < n.expand().size(); i++) {
Node nxt = n.expand().get(i); // Note dukeling suggestion here, I don't know what's behind expand()
if (!close.contains(nxt)) {
FIFO.add(nxt); close.add(nxt);
}
}
}
return false;
}
由于使用close.contains(),它的复杂度也很差(用O(NM)代替O(N + M),其中N-节点数,M-边缘数)。
您应该在Node上添加内部bool标志“ used”(然后get(i)将提供有关此信息的必需信息)。
如果不可能,则应在每个节点上添加标识符(int),以便可以在本地布尔数组(used [id])中将其标记为已访问。 但是,如果节点数对于本地数组而言太大(最多10 ^ 6),那么我认为根本就不会使用bfs。
Dukeling提到的UPD HashSet可能在中级情况下提供O(N + M),而在最坏情况下提供O(NM)。 TreeSet可以提供稳定的O(MlogN)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.