我实施了一个通用的Dijkstra搜索:
public void search(Vertex source) {
source.minDistance = 0;
PriorityQueue<Vertex> vertexQueue = new PriorityQueue<Vertex>();
vertexQueue.add(source);
while (!vertexQueue.isEmpty()) {
Vertex u = vertexQueue.poll();
for (Edge e : u.edges) {
Vertex v = e.target;
int weight = e.weight;
int distance = u.minDistance + weight;
if (distance < v.minDistance) {
vertexQueue.remove(v);
v.minDistance = distance ;
v.previous = u;
vertexQueue.add(v);
}
}
}
}
加速的方法包括:
此搜索将用作使用Yen算法实现k最短路径的基础。
同时在算法上同时应用BOTH加速可以缩短搜索时间,还是会因为两者的使用而导致性能下降?
此外,还有可以实施的进一步加速吗?
答案 0 :(得分:1)
java.util.PriorityQueue.remove
是O(n)操作。如果要使用此PriorityQueue,最好在PriorityQueue中允许重复顶点,但仅在第一次轮询时处理顶点:
class Vertex {
// existing members
boolean visited;
}
和
Vertex u = vertexQueue.poll();
if (u.visited) continue;
u.visited = true;
虽然这会将优先级队列的大小增加到d(最大节点度),因此将运行时间更改为O(dn log(nd)),即O(dn(log n +)记录d)),如果d很小,这是可接受的。特别是,如果d是常数(这是许多现实世界中的路径查找问题),则该算法为O(n log n)。
使用基于指针的堆实现(例如fibonacci堆)将允许通过提供成本降低操作来有效地防止堆中的重复,但基于指针的数据结构具有比阵列支持的优先级队列更差的常数因子。此外,斐波那契堆通过常数因子更陡峭,需要在每次操作中触摸更多节点。因此,我怀疑它实际上会比具有重复项的二进制堆慢(假设节点相当小)。
使用双向搜索,我认为你的意思是从两端“并行”运行Dijkstra,直到两者相遇?此优化将独立于队列表示的改进,并且可以很好地组合。
另一个可能的改进是通过利用Yen算法的后续Dijkstra调用的相似性来减少Dijkstra的频率。可能有必要修改Dijkstra,以便我们可以倒回它,而不是从头开始重新开始?唉,我不太了解Yen算法,所以我无法评估这是否会有所帮助。
答案 1 :(得分:0)
我确实认为使用Fibonacci堆会更快,尽管你可能只注意到你多次调用这个函数。使用反向跟踪也可能会有所帮助。
但是,我建议不要使用Yen的算法,而是使用K *算法,它基本上允许你使用A *来解决k-最短路径问题! K *还有一些其他好处,特别是对于非常大的图形的内存使用。
你可以在这里找到一份免费的论文副本:(我认为这篇论文还有一个较新的版本)K∗: A Directed On-The-Fly Algorithm for Finding the k Shortest Paths
希望这有帮助。