如果对于任意两个不同的顶点u和v,存在一个从u到v的有向路径以及从v到u的有向路径,这样的有向图被称为是强连通的。一般来说,一个有向图的顶点可以分割成一些互不相交的最大子集,每个子集的顶点之间可以通过有向图中的有向路径相互访问,这些子集被称为强连通分量。
下面的方法来自《算法设计与分析基础》作者: Anany Levitin 译者: 潘彦
下面三步说的顶点变成死端是递归的dfs出栈的顺序。
第一步:对给定的有向图执行一次DFS遍历,然后按照顶点变成死端的顺序对它们进行编号。
第二步:颠倒有向图所有边方向。
第三步:对于新的有向图,从仍未访问过的顶点中编号最大的顶点开始(而且如果有必要的话,可以重新开始)做一遍DFS遍历。
邻接表
package d;
public class AGraph {
int n,e;
VNode adjlist[];
public AGraph(int n) {
super();
this.n = n;
adjlist=new VNode[n];
}
}
package d;
class ArcNode{
int adjvex; ArcNode nextarc;
ArcNode reverse_nextarc;
public ArcNode() {
}
public ArcNode (int adjvex){
this.adjvex=adjvex;
};
}
package d;
class VNode{//邻接矩阵的顶点也可以用这个
ArcNode firstarc;
ArcNode reverse_firstarc;
int Serial_number;//DFS访问后按照死端编号
char info;
public VNode(char info) {
this.info = info;
}
public VNode() {
super();
}
}
主程序
package d;
import java.util.Comparator;
class Mycomparator implements Comparator<VNode>
{
public int compare(VNode v1,VNode v2)
{
int a=v1.Serial_number;
int b=v2.Serial_number;
if (a>b)
{
return -1;//按照这种方式排序
}
else if (a<b)
{
return 1;
}
return 0;
}
}
public class Main {
public static int top=-1;
public static int[]stack;
//正常的DFS
public static void DFS1(AGraph a)
{ //-1表示未访问,-2表示是起始节点(前面没东西)
stack=new int[a.n];
int visited[]=new int[a.n];
for(int i=0;i<a.n;i++)//如果要求路径的话
visited[i]=-1;//visited设为-1
for(int i=0;i<a.n;i++)
if(visited[i]==-1)//这里也改为-1
dfs3(a,i,visited,-2);//-2表示是起始节点
}
public static void dfs3(AGraph a,int start,int visited[],int before)
{
//visited必须初始化为-1,不然初始化为0
//分不清visited==0是没有被访问还是被访问了前面一个是0
visited[start]=before;
//进栈操作(按照课本上那种进栈顺序)
ArcNode arc=a.adjlist[start].firstarc;
while(arc!=null)
{ if(visited[arc.adjvex]==-1)
{
dfs3(a,arc.adjvex,visited,start);}
arc=arc.nextarc;
}
a.adjlist[start].Serial_number=++top;
stack[top]=start;
}
//反向邻接表的DFS:
public static void reverse_DFS1(AGraph a)
{ //-1表示未访问,-2表示是起始节点(前面没东西)
int visited[]=new int[a.n];
for(int i=0;i<a.n;i++)//如果要求路径的话
visited[i]=-1;//visited设为-1
while(top!=-1)
{
int i=stack[top--];
if(visited[i]==-1)//这里也改为-1
{
System.out.print("当前强连通分量为:");
reverse_dfs3(a,i,visited,-2);//-2表示是起始节点
System.out.println();
}
}
}
public static void reverse_dfs3(AGraph a,int start,int visited[],int before)
{
//visited必须初始化为-1,不然初始化为0
//分不清visited==0是没有被访问还是被访问了前面一个是0
visited[start]=before;
System.out.print(a.adjlist[start].info+" ");
ArcNode arc=a.adjlist[start].reverse_firstarc;
while(arc!=null)
{ if(visited[arc.adjvex]==-1)
{
reverse_dfs3(a,arc.adjvex,visited,start);
}
arc=arc.reverse_nextarc;
}
}
public static void reverse(AGraph a)
{//颠倒有向图的方向,作反向邻接表
ArcNode [] temp=new ArcNode[a.n];//第i个反向时 现在对应的ArcNode
for(int i=0;i<a.n;i++)
{
ArcNode arc=a.adjlist[i].firstarc;
while(arc!=null)
{
if(temp[arc.adjvex]==null)
{
a.adjlist[arc.adjvex].reverse_firstarc=new ArcNode(i);
temp[arc.adjvex]=a.adjlist[arc.adjvex].reverse_firstarc;
}
else
{
temp[arc.adjvex].reverse_nextarc=new ArcNode(i);
temp[arc.adjvex]=temp[arc.adjvex].reverse_nextarc;
}
arc=arc.nextarc;
}
}
}
public static void main(String[] args) {
AGraph a=new AGraph(8);
for(int i=0;i<a.n;i++)
a.adjlist[i]=new VNode((char)('a'+i));
ArcNode arc;
a.adjlist[0].firstarc=new ArcNode(1);
a.adjlist[1].firstarc=new ArcNode(6);
a.adjlist[2].firstarc=new ArcNode(3);
a.adjlist[2].firstarc.nextarc=new ArcNode(4);
a.adjlist[3].firstarc=new ArcNode(1);
a.adjlist[3].firstarc.nextarc=new ArcNode(6);
a.adjlist[4].firstarc=new ArcNode(7);
a.adjlist[5].firstarc=new ArcNode(0);
a.adjlist[5].firstarc.nextarc=new ArcNode(1);
a.adjlist[6].firstarc=new ArcNode(5);
a.adjlist[7].firstarc=new ArcNode(2);
a.adjlist[7].firstarc.nextarc=new ArcNode(3);
DFS1(a);
System.out.println();
/*不能排序的,一排序就会改变数组的顺序
Comparator<VNode> cmp=new Mycomparator();
Arrays.sort(a.adjlist,cmp);
for (int i=0;i<a.n;i++)
{
System.out.print(a.adjlist[i].info+" ");
}
*/
//直接用stack出栈就行就行
reverse(a);
/* ArcNode arcc;
for(int i=0;i<a.n;i++)
{ System.out.print(i);
arcc=a.adjlist[i].reverse_firstarc;
while(arcc!=null)
{
System.out.print(arcc.adjvex);
arcc=arcc.reverse_nextarc;
}
System.out.println();
}*/
reverse_DFS1(a);
}
}