首先介绍什么是强连接。顶点之间的强连接就是如果v能到达w,那么w也能到达v。顶点之间的强连接就表示顶点之间可以双向到达,也就是说两个顶点在一个回路上。
介绍了强连接,那什么是强连接部件呢?强连接部件就是能够相互到达的所有顶点的集合。一个图中可能会有多个强连接。
强连接在离散数学中属于等价关系,也就是说它具有反射性,相反性,传递性。
强连接在生物学中有所应用,食物链就是一个例子。下图展示了一个很小的食物链。
在食物链中,强连接部件表示在同一个部件中的生物共享相同的能量流。
强连接部件在软件工程中也有应用。一个软件中有许多模块,如果将软件中的模块看成顶点,将模块之间的依赖关系看成图论中的边,那么这就是一个有向图。在同一个强连接部件中的模块之间耦合度是比较高的。按照软件设计原则,耦合度高的模块往往要放在一个包中。所以,强连接部件可以检测模块之间的耦合度,可以软件结构的优化起到指导作用。
为了计算出一个有向图中有多少强连接部件,世界上有一种名叫Kosaraj Sharir算法,这种算法非常简单,但是比较神秘,一般的人无法直观地看出为什么这样算能够得到正确的结果。
这个算法的分为两个阶段。第一个阶段就是对有向图的反图进行拓扑排序,注意是反图。第二个阶段就像连接部件算法一样,按照排序结果,对未曾访问过的节点执行DFS。
有了这样的思路,那么代码就马上出来了:
public class StrongComponent {
private boolean[] visited;
private int[] id;
private int count;
public StrongComponent(Digraph G) {
visited = new boolean[G.V()];
id = new int[G.V()];
// 计算反图的拓扑排序
Digraph R = G.reverse();
Iterable<Integer> sort = new DepthFirstOrder(R).sort();
// 对每个未曾访问过的顶点执行dfs
for (int v : sort) {
if (!visited[v]) {
dfs(G, v);
count++;
}
}
}
public int count() {
return count;
}
public boolean stronglyConnected(int v, int w) {
return id[v] == id[w];
}
public int id(int v) {
return id[v];
}
private void dfs(Digraph G, int v) {
visited[v] = true;
id[v] = count;
for (int w : G.adj(v)) {
if (!visited[w]) {
dfs(G, w);
}
}
}
}原文地址:http://blog.csdn.net/caipeichao2/article/details/32157989