JGraphT 中的“GetDiameter”函数是否占用大量内存?
Do the function “GetDiameter” in JGraphT cost much internal memory?
问题来了:
最近我想用 JGraphT 从一个有 500 万 vertices.But 的图表中获取直径它显示 "out of memory java heap space" 即使我添加 -Xmx 500000m.How 我能解决这个问题吗?非常感谢!
这是我的部分代码:
public static void main(String[] args) throws URISyntaxException,ExportException,Exception {
Graph<Integer, DefaultEdge> subGraph = createSubGraph();
System.out.println(GetDiameter(subGraph));
}
private static Graph<Integer, DefaultEdge> createSubGraph() throws Exception
{
Graph<Integer, DefaultEdge> g = new DefaultUndirectedGraph<>(DefaultEdge.class);
int j;
String edgepath = "sub_edge10000.txt";
FileReader fr = new FileReader(edgepath);
BufferedReader bufr = new BufferedReader(fr);
String newline = null;
while ((newline = bufr.readLine())!=null) {
String[] parts = newline.split(":");
g.addVertex(Integer.parseInt(parts[0]));
}
bufr.close();
fr = new FileReader(edgepath);
bufr = new BufferedReader(fr);
while ((newline = bufr.readLine())!=null) {
String[] parts = newline.split(":");
int origin=Integer.parseInt(parts[0]);
parts=parts[1].split(" ");
for(j=0;j<parts.length;j++){
int target=Integer.parseInt(parts[j]);
g.addEdge(origin,target);
}
}
bufr.close();
return g;
}
private static double GetDiameter(Graph<Integer, DefaultEdge> subGraph)
{
GraphMeasurer g=new GraphMeasurer(subGraph,new JohnsonShortestPaths(subGraph));
return g.getDiameter();
}
如果 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 库中 class JohnsonShortestPaths
的源代码。
问题来了: 最近我想用 JGraphT 从一个有 500 万 vertices.But 的图表中获取直径它显示 "out of memory java heap space" 即使我添加 -Xmx 500000m.How 我能解决这个问题吗?非常感谢!
这是我的部分代码:
public static void main(String[] args) throws URISyntaxException,ExportException,Exception {
Graph<Integer, DefaultEdge> subGraph = createSubGraph();
System.out.println(GetDiameter(subGraph));
}
private static Graph<Integer, DefaultEdge> createSubGraph() throws Exception
{
Graph<Integer, DefaultEdge> g = new DefaultUndirectedGraph<>(DefaultEdge.class);
int j;
String edgepath = "sub_edge10000.txt";
FileReader fr = new FileReader(edgepath);
BufferedReader bufr = new BufferedReader(fr);
String newline = null;
while ((newline = bufr.readLine())!=null) {
String[] parts = newline.split(":");
g.addVertex(Integer.parseInt(parts[0]));
}
bufr.close();
fr = new FileReader(edgepath);
bufr = new BufferedReader(fr);
while ((newline = bufr.readLine())!=null) {
String[] parts = newline.split(":");
int origin=Integer.parseInt(parts[0]);
parts=parts[1].split(" ");
for(j=0;j<parts.length;j++){
int target=Integer.parseInt(parts[j]);
g.addEdge(origin,target);
}
}
bufr.close();
return g;
}
private static double GetDiameter(Graph<Integer, DefaultEdge> subGraph)
{
GraphMeasurer g=new GraphMeasurer(subGraph,new JohnsonShortestPaths(subGraph));
return g.getDiameter();
}
如果 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 库中 class JohnsonShortestPaths
的源代码。