如何基于JGraphT框架对有向图进行正向与反向遍历?
嘿,我来帮你搞定JGraphT 1.1.0里有向图的正向和反向遍历问题!你已经搭好了基础的有向图结构,先帮你补全一下代码里没写完的那条边,接下来咱们一步步实现两种遍历,甚至可以让它们同时跑起来~
首先补全你的图创建代码:
final Graph<String, DefaultEdge> directedGraph = new DefaultDirectedGraph<>(DefaultEdge.class); directedGraph.addVertex("v1"); directedGraph.addVertex("v2"); directedGraph.addVertex("v3"); directedGraph.addVertex("v4"); directedGraph.addEdge("v1", "v4"); directedGraph.addEdge("v4", "v2"); directedGraph.addEdge("v2", "v3"); // 补全这条未完成的边
一、正向遍历(常规路径遍历)
JGraphT自带了现成的迭代器,直接用就能实现BFS(广度优先)或DFS(深度优先)遍历,完全不用自己造轮子:
正向BFS遍历示例
System.out.println("正向BFS遍历结果:"); BreadthFirstIterator<String, DefaultEdge> bfsIterator = new BreadthFirstIterator<>(directedGraph); while (bfsIterator.hasNext()) { String vertex = bfsIterator.next(); System.out.print(vertex + " "); // 如果需要同时输出边信息,可以遍历当前顶点的出边 for (DefaultEdge edge : directedGraph.outgoingEdgesOf(vertex)) { System.out.print("(" + directedGraph.getEdgeSource(edge) + "->" + directedGraph.getEdgeTarget(edge) + ") "); } }
正向DFS遍历示例
System.out.println("\n正向DFS遍历结果:"); DepthFirstIterator<String, DefaultEdge> dfsIterator = new DepthFirstIterator<>(directedGraph); while (dfsIterator.hasNext()) { String vertex = dfsIterator.next(); System.out.print(vertex + " "); }
二、反向遍历(沿入边方向遍历)
要实现反向遍历,JGraphT提供了一个非常方便的ReverseGraph类——它会创建原有有向图的反向视图(不会复制数据,只是反转所有边的方向),这样你就能用和正向遍历完全一样的方式来遍历这个反向图,等价于沿原图形的入边方向遍历。
基于ReverseGraph的反向遍历示例
// 创建反向图视图(原图形修改会同步到这里,无需额外维护) Graph<String, DefaultEdge> reversedGraph = new ReverseGraph<>(directedGraph); // 反向BFS遍历(对应原图形的反向路径) System.out.println("\n反向BFS遍历结果:"); BreadthFirstIterator<String, DefaultEdge> reversedBfsIterator = new BreadthFirstIterator<>(reversedGraph); while (reversedBfsIterator.hasNext()) { String vertex = reversedBfsIterator.next(); System.out.print(vertex + " "); // 这里的"出边"就是原图形的入边 for (DefaultEdge edge : reversedGraph.outgoingEdgesOf(vertex)) { System.out.print("(" + reversedGraph.getEdgeSource(edge) + "->" + reversedGraph.getEdgeTarget(edge) + ") "); } }
如果你不想创建反向图,也可以直接遍历每个顶点的入边来手动实现反向遍历:
// 手动遍历原图形的入边 System.out.println("\n手动反向遍历(遍历入边):"); for (String vertex : directedGraph.vertexSet()) { System.out.print("顶点" + vertex + "的入边:"); for (DefaultEdge edge : directedGraph.incomingEdgesOf(vertex)) { System.out.print("(" + directedGraph.getEdgeSource(edge) + "->" + directedGraph.getEdgeTarget(edge) + ") "); } System.out.println(); }
三、同时进行正向与反向遍历
如果要让两种遍历同时执行,用Java多线程就能轻松实现,比如创建两个独立的线程分别处理正向和反向遍历:
// 正向遍历线程 Thread forwardThread = new Thread(() -> { System.out.println("[正向线程] 开始遍历:"); BreadthFirstIterator<String, DefaultEdge> iterator = new BreadthFirstIterator<>(directedGraph); while (iterator.hasNext()) { System.out.print("[正向线程] " + iterator.next() + " "); } System.out.println("\n[正向线程] 遍历结束"); }); // 反向遍历线程 Thread reverseThread = new Thread(() -> { System.out.println("[反向线程] 开始遍历:"); Graph<String, DefaultEdge> reversedGraph = new ReverseGraph<>(directedGraph); BreadthFirstIterator<String, DefaultEdge> iterator = new BreadthFirstIterator<>(reversedGraph); while (iterator.hasNext()) { System.out.print("[反向线程] " + iterator.next() + " "); } System.out.println("\n[反向线程] 遍历结束"); }); // 启动两个线程 forwardThread.start(); reverseThread.start(); // 可选:等待两个线程都执行完毕 try { forwardThread.join(); reverseThread.join(); } catch (InterruptedException e) { e.printStackTrace(); }
内容的提问来源于stack exchange,提问作者Hector




