求强连通分支的基本步骤有:
1、建立原图连接表G和其转置图连接表T
2、对原图G进行深度搜索
3、对原图进行拓扑排序
4、对图再按原图G拓扑排序后的顺序对转置图T进行深搜
5、输出强连通分支
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int adjvex;
struct node *next;
}EdgeNode;
typedef struct vnode
{
char c;
int dis;;//节点的发现时间
int fish;//节点的完成时间
int pre;//节点深搜时的前驱
int color;//1代表白色表示该点尚未发现 2代表灰色现已发现 3代表黑色表示与它邻接的边已发现
EdgeNode *firstedge;
}VertexNode;
typedef struct
{
int dis;//用于标记AdjList中的 dis
int id; //用于标记AdjList向量的序号
}point;
int time;//时间计数器
void InPut(VertexNode G[],VertexNode T[],int n,int e) //节点及边的录入 以及建立图G邻接表及它的转置T邻接表
{
int i,j,s,d,find;
char ch1,ch2;
EdgeNode *p,*q;
printf("请输入一次输入所有字符节点 且第一个输入的点默认为源节点\n");
for(i=0;i<n;i++)
{
scanf("%c ",&G[i].c);
T[i].c=G[i].c;
G[i].firstedge=T[i].firstedge=NULL;
}
printf("请输入各条边\n");
for(i=1;i<=e;i++)//建立邻接表 由于是无向图则要申请两个节点p和q
{
find=0;
scanf("%c %c ",&ch1,&ch2);
for(j=0;find!=2&&j<n;j++)
if(ch1==G[j].c)
{
s=j;
find++;
}
else if(ch2==G[j].c)
{
d=j;
find++;
}
p=(EdgeNode*)malloc(sizeof(EdgeNode));//用于原图G连接表的建立
p->adjvex=d;
p->next=G[s].firstedge;
G[s].firstedge=p;
q=(EdgeNode*)malloc(sizeof(EdgeNode));//用于原图G的转置T连接表的建立
q->adjvex=s;
q->next=T[d].firstedge;
T[d].firstedge=q;
}
}
void DFS_VISIT(VertexNode AdjList[],int u)//深度搜索递归
{
int v;
EdgeNode *p;
AdjList[u].color=2;//u节点已发现 标记为灰色
time++;
AdjList[u].dis=time;
p=AdjList[u].firstedge;
while(p)
{
v=p->adjvex;
if(AdjList[v].color==1)
{
AdjList[v].pre=u;
DFS_VISIT(AdjList,v);
}
p=p->next;
}
AdjList[u].color=3;//u节点所有邻接点均已发现,即完成任务,标记为黑色
AdjList[u].fish=time=time+1;//标记完成时间
}
void DFS(VertexNode AdjList[],int n)//深度搜索
{
int i;
for(i=0;i<n;i++)
{
AdjList[i].color=1;//1代表白色表示该点尚未发现
AdjList[i].pre=-1;//前驱向量初始化
}
time=0;
for(i=0;i<n;i++)
if(AdjList[i].color==1)
DFS_VISIT(AdjList,i);
}
void printpath(VertexNode AdjList[],int i,int n)//递归输出源点到各点的路径
{
if(AdjList[i].pre==-1)
{
printf("%c->",AdjList[i].c);
AdjList[i].color=4;
return ;
}
else
{
printpath(AdjList,AdjList[i].pre,n);
if(i==n)
printf("%c",AdjList[i].c);
else
printf("%c->",AdjList[i].c);
AdjList[i].color=4;
}
}
int cmpdis(const void *a,const void *b)//用于节点发现时间由大到小排列
{
return( ((point*)b)->dis-((point*)a)->dis );//
}
void print(VertexNode AdjList[],int n)输出源点到各点的长度及路径
{
int i,j,id,count;
point p[10001];
for(i=0;i<n;i++)
{
p[i].dis=AdjList[i].dis;
p[i].id=i;
}
qsort(p,n,sizeof(p[0]),cmpdis);//时间按发现时间由大到小排序 利于T连接表的强连通量的深搜
count=0;//记录强连通分支的个数
for(i=0;i<n;i++)
{
id=p[i].id;//发现时间较晚的节点 在T中的位置
if(AdjList[id].pre!=-1&&AdjList[id].color==3)
{
printf("强连通分支%d: ",++count);
for(j=0;j<n;j++)
AdjList[j].color=3;
printpath(AdjList,id,id);//递归输出源点到各点的路径
printf("\n");
}
else if(AdjList[id].pre==-1&&AdjList[id].color==3)
{
printf("强连通分支%d: ",++count);
printf("%c\n",AdjList[id].c);
}
}
}
int cmpfish(const void *a,const void *b)
{
return( ((VertexNode*)b)->fish-((VertexNode*)a)->fish );//从大到小排列
}
void TOPOLOGICAL_SORT(VertexNode AdjList[],int n)//拓扑排序
{
// int i;
qsort(AdjList,n,sizeof(AdjList[0]),cmpfish);//时间按完成时间由大到小排序
/* for(i=0;i<n;i++)//排序输出
printf("%3c ",AdjList[i].c);
printf("\n");
for(i=0;i<n;i++)
printf("%3d ",AdjList[i].fish);
printf("\n"); */
}
void DFS2(VertexNode T[],int n)
{
int i;
qsort(T,n,sizeof(T[0]),cmpfish);//时间按完成时间由大到小排序
for(i=0;i<n;i++)
{
T[i].color=1;//1代表白色表示该点尚未发现
T[i].pre=-1;//前驱向量初始化
}
time=0;
for(i=0;i<n;i++)
if(T[i].color==1)
DFS_VISIT(T,i);
print(T,n);
}
int main()
{
freopen("1.txt","r",stdin);
int n,e;
int i;
VertexNode G[10001];//原连接表图
VertexNode T[10001];//原连接图的转置
printf("请输入字符节点的个数N 和边的数目E:\n");
scanf("%d%d ",&n,&e);
InPut(G,T,n,e); //节点及边的录入 以及建立邻接表
DFS(G,n);// 深度搜索1
// print(G,n);
for(i=0;i<n;i++)
T[i].fish=G[i].fish;
TOPOLOGICAL_SORT(G,n);//拓扑排序
DFS2(T,n);//拓扑排序后再对图G的转置图T进行深搜
return 0;
}