Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使我的Dijkstra算法更有效_Java_Algorithm_Graph Theory - Fatal编程技术网

Java 如何使我的Dijkstra算法更有效

Java 如何使我的Dijkstra算法更有效,java,algorithm,graph-theory,Java,Algorithm,Graph Theory,我有一个有向网络模型,它由一组节点组成,这些节点通过链接连接起来,这些链接随着模型的每次迭代而增长。为了在最终的模型迭代中找到平均最短路径,我实现了Dijkstra算法,该算法计算从所有节点到所有节点的最短路径。更具体地说,该算法计算从网络3000个节点到所有其他3000个节点的最短路径(如果存在路径),大约9000000个路径长度,然后找到平均路径长度。当我尝试此操作时,我的内存不足。我能够得到平均路径长度,直到大约500个节点,其中大约250000个路径长度是在12小时内计算出来的。我的问题

我有一个有向网络模型,它由一组节点组成,这些节点通过链接连接起来,这些链接随着模型的每次迭代而增长。为了在最终的模型迭代中找到平均最短路径,我实现了Dijkstra算法,该算法计算从所有节点到所有节点的最短路径。更具体地说,该算法计算从网络3000个节点到所有其他3000个节点的最短路径(如果存在路径),大约9000000个路径长度,然后找到平均路径长度。当我尝试此操作时,我的内存不足。我能够得到平均路径长度,直到大约500个节点,其中大约250000个路径长度是在12小时内计算出来的。我的问题是,有没有办法以一种更有效的方式改进代码?或者,计算这么多路径是不可行的

下面的代码。。。该算法本身改编自Vogella

网络中的节点表示树,边或链接表示网络

Dijstra算法

package network;

imports...

public class DijkstraAlgorithm {
    private Context<Object> context;
    private Geography<Object> geography;
    private int id; 
    List<Tree> vertices = Tree.getVertices();
    List<Nets> edges = Nets.getEdges();
    private Set<Tree> settledNodes;
    private Set<Tree> unSettledNodes;
    private Map<Tree, Tree> predecessors;
    private Map<Tree, Integer> distance;

public DijkstraAlgorithm(Graph graph) {
    this.context = context;
    this.geography = geography;
    this.id = id;
    this.vertices = vertices;
    this.edges = edges;
}


setters and getters....

public void execute(Tree source){
    settledNodes = new HashSet<Tree>();
    unSettledNodes = new HashSet<Tree>();
    distance = new HashMap<Tree, Integer>();
    predecessors = new HashMap<Tree, Tree>();
    distance.put(source, 0);
    unSettledNodes.add(source);
    while (unSettledNodes.size()>0){
        Tree node = getMinimum(unSettledNodes);
        settledNodes.add(node);
        unSettledNodes.remove(node);
        findMinimalDistances(node);
    }
}

private void findMinimalDistances(Tree node){
    List<Tree>adjacentNodes = getNeighbors(node);
    for (Tree target: adjacentNodes){
        if (getShortestDistance(target)>getShortestDistance(node)+getDistance(node,target)){
            distance.put(target, getShortestDistance(node) + getDistance(node, target));
            predecessors.put(target, node);
            unSettledNodes.add(target);
        }

    }
}

private int getDistance(Tree node, Tree target){
    for (Nets edge: edges){
        if (edge.getStartTrees().equals(node) && edge.getEndTrees().equals(target)){
            return edge.getId();
        }
    }
    throw new RuntimeException("Should not happen");
}

private List<Tree> getNeighbors(Tree node){
    List<Tree> neighbors = new ArrayList<Tree>();
    for (Nets edge: edges) {
        if(edge.getStartTrees().equals(node) && !isSettled(edge.getEndTrees())){
            neighbors.add(edge.getEndTrees());
        }
    }
    return neighbors;
}

private Tree getMinimum(Set<Tree>vertexes){
    Tree minimum = null;
    for (Tree vertex: vertexes) {
        if (minimum == null){
            minimum = vertex;
        } else {
            if (getShortestDistance(vertex)< getShortestDistance(minimum)){
                minimum = vertex;
            }
        }
    }

    return minimum;

}

private boolean isSettled(Tree vertex){
    return settledNodes.contains(vertex);
}

private int getShortestDistance(Tree destination) {
    Integer d = distance.get(destination);
    if (d == null) {
        return Integer.MAX_VALUE;
    } else {
        return d;
    }
}

public LinkedList<Tree> getPath(Tree target){
    LinkedList<Tree>path = new LinkedList<Tree>();
    Tree step = target;
    if(predecessors.get(step)== null){
        return null;
    }
    path.add(step);
    while (predecessors.get(step)!=null){
        step = predecessors.get(step);
        path.add(step);

    }
    Collections.reverse(path);
    return path;
}



}
图表


您可以进行一些优化。例如,使用斐波那契堆甚至标准java优先级队列肯定会加快速度。但是,对于如此大的数据集,内存问题可能会持续存在。处理如此大的数据集的唯一真正方法是使用分布式实现。我相信Spark Graphx库中有一个最短路径实现,您可以使用它

一个快速改进是移动生产线:

dijkstra.execute(vertices.get(i));
最多6行,所以它在i循环中,但不是j循环

这将使运行时的节点数提高3000倍


因为Dijkstra的算法计算从起始节点到所有目的节点的最短路径,所以它仍然会给出相同的结果,因此,没有必要为每对开始/结束重新运行它。

内存限制只是物理上的——如果X>Y,你就无法将X磅的东西放入Y磅的袋子中。你唯一的希望似乎是在多台机器上并行和分布计算:从运行时角度看,最大的问题是每次迭代都在搜索在整个集合中,为minimun。理想情况下,Dijkstra使用一个MinHeap,一个成本最低的节点位于其根上的堆。我没有仔细阅读代码,但是您是否为每对顶点运行一次Dijkstra算法?用弗洛伊德-沃沙尔代替怎么样。维基百科:只需执行一次算法,就可以找到所有顶点对之间最短路径的长度和权重。提醒一下,Floyd Washall的复杂度是| V | 3,Dijkstra的复杂度是| E |+|V | log | V |。通过运行Dijkstra的| V |顶点,它将是| E |+| V | log | V |*| V |,我只想指出,通过这样做,模型能够计算所有9000000条路径长度,并在1小时内找到平均值。
dijkstra.execute(vertices.get(i));