Java 多个加速Dijkstra的解决方案会降低性能吗?
我已经实现了一个通用的Dijkstra搜索:Java 多个加速Dijkstra的解决方案会降低性能吗?,java,algorithm,graph-algorithm,path-finding,Java,Algorithm,Graph Algorithm,Path Finding,我已经实现了一个通用的Dijkstra搜索: public void search(Vertex source) { source.minDistance = 0; PriorityQueue<Vertex> vertexQueue = new PriorityQueue<Vertex>(); vertexQueue.add(source); while (!vertexQueue.isEmpty()) { Vertex
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);
}
}
}
}
公共无效搜索(顶点源){
source.minDistance=0;
PriorityQueue vertexQueue=新建PriorityQueue();
添加(源);
而(!vertexQueue.isEmpty()){
Vertex u=vertexQueue.poll();
对于(边e:u边){
顶点v=e.目标;
int-weight=e.weight;
内部距离=u.minDistance+重量;
if(距离小于v.minDistance){
移除(v);
v、 距离=距离;
v、 先前=u;
vertexQueue.add(v);
}
}
}
}
加速的方法包括:
- 斐波那契堆
- 双向搜索
此外,是否可以实现进一步的加速?java.util.PriorityQueue.remove是一种O(n)操作。如果要使用此PriorityQueue,最好在PriorityQueue中允许重复顶点,但仅在第一次轮询顶点时处理该顶点:
class Vertex {
// existing members
boolean visited;
}
及
虽然这会将优先级队列的大小增加多达d(最大节点度)的一倍,因此会将运行时更改为O(dn log(nd)),即O(dn(logn+logd)),但如果d很小,这可能是可以接受的。特别是,如果d是常数(这在许多实际的路径查找问题中都是如此),那么该算法就是O(n logn)
使用基于指针的堆实现(如fibonacci堆)可以通过提供成本降低操作来有效防止堆中的重复,但基于指针的数据结构的常量因子比基于数组的优先级队列要差。此外,fibonacci堆的陡峭度是常数因子,在每次操作中需要接触更多的节点。因此,我怀疑它实际上会比具有重复项的二进制堆慢(假设节点相当小)
对于双向搜索,我想你的意思是从两端“平行”运行Dijkstra,直到两者相遇?这种优化将独立于队列表示的改进,并且可以很好地结合起来
另一个可能的改进是通过利用Yen算法的后续Dijkstra调用的相似性来减少调用Dijkstra的频率。是否值得修改迪杰克斯特拉,这样我们就可以倒带它,而不是从头开始?唉,我不太了解Yen算法,所以我无法评估这是否有帮助。我确实认为使用Fibonacci堆会更快,尽管您可能只会注意到如果多次调用此函数。使用回溯也可能会有更大的帮助 但是,我建议不要使用Yen的算法,而是使用K*算法,它基本上允许您使用A*来解决K-最短路径问题!K*还有一些其他的好处,特别是对于非常大的图的内存使用 你可以在这里找到这篇论文的免费副本:(我想这篇论文还有一个更新的更长的版本)
希望这能有所帮助。斐波那契堆的问题是它们的常数很差。在使用原始优先级队列(任意删除
O(n)
和fibonacci堆(常数较差)之间有一些中间点)。@amit取决于具体情况。如果距离相差很大,那就更好了
Vertex u = vertexQueue.poll();
if (u.visited) continue;
u.visited = true;