看论文的时候,看到Kosaraju算法。Kosaraju是一个强连通分图的发现算法,如有代码中有详细的注释,所以就不赘述了。直接上码(使用webgraph库实现,在我之前的文章中,对webgraph有相关的介绍):
package cn.edu.dlut.wisdom;import it.unimi.dsi.fastutil.ints.*;import it.unimi.dsi.fastutil.objects.*;import it.unimi.dsi.webgraph.*;import java.util.Comparator;/*** @author You Wang* Kosaraju算法,用来发现强连通分量* 算法过程如下:* G:有向图;S:空栈* while S中不包含G中所有顶点* 任选一个不在S中的节点v* 从v开始进行深度优先搜素,每次将访问到的节点u压入S中* 反转G中所有的边* while S非空* 从S中弹出结点v* 从v开始进行深度优先搜索,所有访问到的结点构成强连通分图,记录下来* 从G和S中删除这些结点*/public class Kosaraju {private ImmutableGraph graph;private ImmutableGraph igraph;private ImmutableGraph workGraph;private ObjectAVLTreeSet<IntAVLTreeSet> sccs;private IntArrayList stack;private boolean[] visited;private int numNodes;public Kosaraju(ImmutableGraph graph) {this.graph = graph;igraph = Transform.transpose(graph);numNodes = graph.numNodes();}public Kosaraju(ImmutableGraph graph, ImmutableGraph igraph) {this.graph = graph;this.igraph = igraph;numNodes = graph.numNodes();}public ObjectAVLTreeSet<IntAVLTreeSet> compute() {stack = new IntArrayList();visited = new boolean[numNodes];workGraph = graph;// dfs the graph, adding nodes to the stackfor(int i = 0; i < numNodes; i++)if(!stack.contains(i))dfs(i, true);workGraph = igraph;Comparator cmp = new Comparator() {public int compare(Object o1, Object o2) {if(o1 instanceof IntAVLTreeSet && o2 instanceof IntAVLTreeSet) {IntAVLTreeSet s1 = (IntAVLTreeSet)o1;IntAVLTreeSet s2 = (IntAVLTreeSet)o2;if (s1.size() != s2.size())return s1.size() - s2.size();else{int[] a1 = s1.toIntArray();int[] a2 = s2.toIntArray();for (int i = 0; i < a1.length; i++)if (a1[i] != a2[i])return a1[i] - a2[i];return 0;}}elsethrow new IllegalArgumentException("The argument must be an IntAVLTreeSet");}};sccs = new ObjectAVLTreeSet<IntAVLTreeSet>(cmp);while(!stack.isEmpty()) {IntAVLTreeSet component = new IntAVLTreeSet();int v = stack.popInt();component.add(v);dfs(v, false);// any components we visited are strongly connected// remove them from the starck and add them to the componentIntIterator it = stack.iterator();while(it.hasNext()) {int n = it.nextInt();if(!visited[n]) {component.add(n);it.remove();}}if(component.size() != 0)sccs.add(component);}return sccs;}private void dfs(int node, boolean forward) {visited[node] = forward;if(workGraph.outdegree(node) == 0) {if(forward)stack.push(node);return;}for(int n : workGraph.successorArray(node))if(visited[n] != forward)dfs(n, forward);if(forward)stack.push(node);}}
其中的set排序,个人感觉不尽完美,不知道各位有何高见,欢迎指正。