JGraphT中的“ GetDiameter”功能是否占用大量内部存储器?

时间:2019-04-29 02:18:11

标签: jgrapht

这是问题所在: 最近,我想使用JGraphT从具有500万个顶点的图形中获取直径。但是它表明即使我添加了-Xmx 500000m,“内存不足的Java堆空间”也如何解决?非常感谢!

这是我的代码的一部分:

bytes

1 个答案:

答案 0 :(得分:1)

如果n是图形的顶点数,则库在内部创建一个n×n矩阵来存储所有最短路径。因此,是的,内存消耗很大。这是由于以下事实:库在内部使用全对最短路径算法,例如Floyd-Warshall或Johnson的算法。

由于没有足够的内存,您可以尝试使用单源最短路径算法来计算直径。这会比较慢,但是不需要那么多内存。下面的代码演示了此假设,假设无向图和非负权重,并因此使用Dijkstra算法。

package org.myorg.diameterdemo;

import org.jgrapht.Graph;
import org.jgrapht.alg.interfaces.ShortestPathAlgorithm;
import org.jgrapht.alg.interfaces.ShortestPathAlgorithm.SingleSourcePaths;
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.builder.GraphTypeBuilder;
import org.jgrapht.util.SupplierUtil;

public class App {

    public static void main(String[] args) {

        Graph<Integer, DefaultWeightedEdge> graph = GraphTypeBuilder
                .undirected()
                .weighted(true)
                .allowingMultipleEdges(true)
                .allowingSelfLoops(true)
                .vertexSupplier(SupplierUtil.createIntegerSupplier())
                .edgeSupplier(SupplierUtil.createDefaultWeightedEdgeSupplier())
                .buildGraph();

        Integer a = graph.addVertex();
        Integer b = graph.addVertex();
        Integer c = graph.addVertex();
        Integer d = graph.addVertex();
        Integer e = graph.addVertex();
        Integer f = graph.addVertex();

        graph.addEdge(a, c);
        graph.addEdge(d, c);
        graph.addEdge(c, b);
        graph.addEdge(c, e);
        graph.addEdge(b, e);
        graph.addEdge(b, f);
        graph.addEdge(e, f);

        double diameter = Double.NEGATIVE_INFINITY;
        for(Integer v: graph.vertexSet()) { 
            ShortestPathAlgorithm<Integer, DefaultWeightedEdge> alg = new DijkstraShortestPath<Integer, DefaultWeightedEdge>(graph);

            SingleSourcePaths<Integer, DefaultWeightedEdge> paths = alg.getPaths(v);
            for(Integer u: graph.vertexSet()) { 
                diameter = Math.max(diameter, paths.getWeight(u));  
            }
        }

        System.out.println("Graph diameter = " + diameter);
    }

}

如果权重为负,则需要在上面的代码中使用new BellmanFordShortestPath<>(graph)用Bellman-Ford替换最短路径算法。

此外,还可以使用Johnson的技术,首先使用Bellman-Ford将边缘权重转换为非负值,然后开始执行对Dijkstra的调用。但是,这将需要不小的改变。查看JGraphT库中类JohnsonShortestPaths的源代码。