在之前的Tarjan算法求连通分量博文中(点此查看),代码实现用到了固定大小数组,扩展起来似乎并不是很方便,在java里这样来实现本身就是不太妥当的,所以下面给出一个更新版本的代码实现:
package test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
public class TarjanSCC<NodeType> {
int index;
Map<NodeType, LinkedList<NodeType>> graph;
Map<NodeType, Integer> indexMap;
Map<NodeType, Integer> lowLinkMap;
Stack<NodeType> stack;
List<List<NodeType>> result;
public TarjanSCC(Map<NodeType, LinkedList<NodeType>> graph) {
this.index = 0;
this.graph = graph;
this.indexMap = new HashMap<NodeType, Integer>();
this.lowLinkMap = new HashMap<NodeType, Integer>();
this.result = new ArrayList<List<NodeType>>();
}
public List<List<NodeType>> tarjan() {
this.index = 0;
stack = new Stack<NodeType>();
List<List<NodeType>> result = new ArrayList<List<NodeType>>();
for (NodeType v : this.graph.keySet()) {
if (indexMap.get(v) == null) {
result.addAll(this.strongConnect(v));
}
}
return result;
}
public List<NodeType> getSuccessors(NodeType v,Map<NodeType, LinkedList<NodeType>> graph) {
List<NodeType> successors = new ArrayList<NodeType>();
Set<NodeType> set = graph.keySet();
Iterator<NodeType> it = set.iterator();
while (it.hasNext()) {
NodeType node = it.next();
if (node.equals(v)) {
successors.addAll(graph.get(node));
break;
}
}
return successors;
}
public List<List<NodeType>> strongConnect(NodeType v) {
indexMap.put(v, index);
lowLinkMap.put(v, index);
index++;
stack.push(v);
for (NodeType w : getSuccessors(v, graph)) {
if (indexMap.get(w) == null) {
strongConnect(w);
lowLinkMap.put(v, Math.min(lowLinkMap.get(v), lowLinkMap.get(w)));
} else if (stack.contains(w)) {
lowLinkMap.put(v, Math.min(lowLinkMap.get(v), indexMap.get(w)));
}
}
if (lowLinkMap.get(v).equals(indexMap.get(v))) {
List<NodeType> sccList = new ArrayList<NodeType>();
while (true) {
NodeType w = stack.pop();
sccList.add(w);
if (w.equals(v)) {
break;
}
}
if (sccList.size() > 1) {
result.add(sccList);
}
}
return result;
}
}
下面是主函数调用代码:
package test;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class TestTarjan {
Map<Integer, LinkedList<Integer>> graph = new HashMap<Integer, LinkedList<Integer>>();
public TestTarjan(String path) {
try {
BufferedReader br = new BufferedReader(new FileReader(path));
String[] strArray;
String str;
while ((str = br.readLine()) != null) {
strArray = str.split("\\s");
int a = Integer.parseInt(strArray[0]);
int b = Integer.parseInt(strArray[1]);
if (graph.containsKey(a)) {
graph.get(a).add(b);
} else {
LinkedList<Integer> linkedlist = new LinkedList<Integer>();
linkedlist.add(b);
graph.put(a, linkedlist);
}
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public List<List<Integer>> getResult(){
TarjanSCC<Integer> tarjanScc = new TarjanSCC<Integer>(graph);
return tarjanScc.tarjan();
}
public static void main(String[] args) {
TestTarjan testTarjan = new TestTarjan("c:/tarjan.txt");
System.out.println(testTarjan.getResult());
}
}
这里赋上一组简单的测试数据:
1 2
2 3
3 1
4 2
3 4
3 5
5 6
6 7
7 5
7 8
8 9
9 10
10 8