//有向图的强连通分量:利用深度优先搜索求有向图的强连通分量
//------Kosaraju算法:------\\
//(1)对原图取反,从任意一个顶点开始对反向图进行逆后续DFS遍历
//(2)按照逆后续遍历中栈中的顶点出栈顺序,对原图进行DFS遍历,一次DFS遍历中访问的所有顶点都属于同一强连通分量。
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MAX_VERTEX_NUM 20
#define INFINITY INT_MAX
typedef int Status;
#define OK 1
#define ERROR 0
typedef enum {FALSE,TRUE} Boolean;
typedef int InfoType; //定义弧相关信息为整形
typedef char VertexType; //定义顶点类型为字符型
typedef char ElemType;
//十字链表表示的图结构
typedef struct ArcNode
{
int tailvex,headvex; //该弧所指向的顶点在顺序结构中的位置
struct ArcNode *hlink,*tlink; //分别为与该弧头邻接(同一尾结点)的下一条弧的指针和与该弧尾邻接(同一尾结点)的下一条弧的指针
InfoType *info; //该弧相关信息的指针
}ArcNode; //弧结构
typedef struct VNode
{
VertexType data; //顶点
ArcNode *firstin,*firstout; //分别为该顶点的第一条入弧和第一条出弧
}VNode,OrtList[MAX_VERTEX_NUM]; //顶点结构
typedef struct
{
OrtList vertices; //顶点数组
int vexnum,arcnum; //顶点数和弧数
}OLGraph; //十字链表表示的图结构
//树结构:孩子兄弟链
typedef struct CSNode
{
ElemType data;
struct CSNode *firstchild,*nextsibling;
}CSNode,*CSTree;
Status CreateDG(OLGraph *G);
int LocateVex(OLGraph G,VertexType v);
void DGDFSTraverse(OLGraph G);
void DGDFS(OLGraph G,int v,int *count);
void DGDFSForest(OLGraph G,CSTree *T);
void DGDFSTree(OLGraph G,int v,CSTree *t);
void CSTreeTraverse(CSTree T);
int FirstAdjVex_Out(OLGraph G,int v);
int NextAdjVex_Out(OLGraph G,int v,int w);
int FirstAdjVex_In(OLGraph G,int v);
int NextAdjVex_In(OLGraph G,int v,int w);
int finished[MAX_VERTEX_NUM];
Boolean visited[MAX_VERTEX_NUM];
int main()
{
OLGraph *G;
G=(OLGraph *)malloc(sizeof(OLGraph));
CSTree *T;
T=(CSTree *)malloc(sizeof(CSTree));
CreateDG(G);
int i;
//打印十字链表
printf("打印十字链表表示的图结构:\n");
for(i=0;i<G->vexnum;i++)
{
ArcNode *p;
p=(ArcNode *)malloc(sizeof(ArcNode));
p=G->vertices[i].firstout;
printf("%c ",G->vertices[i].data);
while(p)
{
int t;
t=p->headvex;
printf("%c ",G->vertices[t].data);
p=p->tlink;
}
printf("\n");
}
printf("深度优先遍历:\n");
DGDFSTraverse(*G);
for(i=0;i<G->vexnum;i++)
printf("%d ",finished[i]);
printf("\n深度优先生成森林:\n");
DGDFSForest(*G,T);
printf("\n打印森林:\n");
CSTreeTraverse(*T);
return 0;
}
int LocateVex(OLGraph G,VertexType v)
{
int i;
for(i=0;i<G.vexnum;i++)
if(G.vertices[i].data==v)
return i;
return -1;
}
//创建十字链表表示的有向图
Status CreateDG(OLGraph *G)
{
int i,IncInfo;
printf("输入顶点数量:");
scanf("%d",&G->vexnum);
printf("输入弧数量:");
scanf("%d",&G->arcnum);
printf("弧是否含有其他信息(否---0,是---1):");
scanf("%d",&IncInfo);
//头结点处理
for(i=0;i<G->vexnum;i++)
{
fflush(stdin);
printf("输入第%d个顶点:",i+1);
scanf("%c",&G->vertices[i].data); //输入头结点的顶点信息
G->vertices[i].firstin=G->vertices[i].firstout=NULL; //初始化头结点的出、入弧指针
}
//弧结点处理
for(i=0;i<G->arcnum;i++)
{
char v1,v2;
int headvex,tailvex;
fflush(stdin);
printf("输入第%d条弧的头结点:",i+1);
scanf("%c",&v1);
fflush(stdin);
printf("输入第%d条弧的尾结点:",i+1);
scanf("%c",&v2);
headvex=LocateVex(*G,v1);
tailvex=LocateVex(*G,v2);
ArcNode *p;
p=(ArcNode *)malloc(sizeof(ArcNode));
p->headvex=headvex;
p->tailvex=tailvex;
//对弧结点的hlink和tlink应用头插法:即将头结点的firstin放在当前弧的hlink后面,再把当前弧放在头结点的firstin后面
p->hlink=G->vertices[headvex].firstin;
G->vertices[headvex].firstin=p;
p->tlink=G->vertices[tailvex].firstout;
G->vertices[tailvex].firstout=p;
if(IncInfo)
{
int info;
printf("输入弧的其他信息:");
scanf("%d",&info);
p->info=&info;
}
else
p->info=NULL;
}
return OK;
}
//求位置v结点的第一个出弧邻接点
int FirstAdjVex_Out(OLGraph G,int v)
{
if(G.vertices[v].firstout)
return G.vertices[v].firstout->headvex;
else
return -1;
}
//求位置v结点就w外的其他出弧邻接点
int NextAdjVex_Out(OLGraph G,int v,int w)
{
ArcNode *p;
p=(ArcNode *)malloc(sizeof(ArcNode));
p=G.vertices[v].firstout;
while(p)
{
if(p->headvex==w || visited[p->headvex])
p=p->tlink;
else
return p->headvex;
}
return -1;
}
//利用深度优先搜索从顶点出发沿弧头到弧尾的方向遍历各顶点,
//并将各顶点的邻接顶点按遍历顺序存储在finished数组中,顶点排在各邻接顶点后面
void DGDFSTraverse(OLGraph G)
{
int i,count;
count=0;
for(i=0;i<G.vexnum;i++)
visited[i]=FALSE;
for(i=0;i<G.vexnum;i++)
if(!visited[i])
{
visited[i]=TRUE;
DGDFS(G,i,&count);
printf("%c ",G.vertices[i].data);
finished[count++]=i; //关键之处:顶点排在其邻接顶点后面
}
}
void DGDFS(OLGraph G,int v,int *count)
{
int i;
for(i=FirstAdjVex_In(G,v);i>=0;i=NextAdjVex_In(G,v,i))
if(!visited[i])
{
visited[i]=TRUE;
printf("%c ",G.vertices[i].data);
finished[(*count)++]=i;
DGDFS(G,i,count);
}
}
//-------以下为深度优先搜索遍历,同时以孩子兄弟链表结构建立有向图的深度优先生成森林-------\\
//求位置v结点的第一个入弧邻接点
int FirstAdjVex_In(OLGraph G,int v)
{
if(G.vertices[v].firstin)
return G.vertices[v].firstin->tailvex;
else
return -1;
}
//求位置v结点就w外的其他入弧邻接点
int NextAdjVex_In(OLGraph G,int v,int w)
{
ArcNode *p;
p=(ArcNode *)malloc(sizeof(ArcNode));
p=G.vertices[v].firstin;
while(p)
{
if(p->tailvex==w || visited[p->tailvex])
p=p->hlink;
else
return p->tailvex;
}
return -1;
}
//按finished数组中各顶点从最后到第一个的顺序,利用深度优先搜索遍历各顶点,生成深度优先生成森林
//森林中根结点的各颗兄弟结点即为各生成树的根结点
void DGDFSForest(OLGraph G,CSTree *T)
{
int i,j;
*T=NULL;
CSTree temp;
temp=(CSTree)malloc(sizeof(CSNode));
for(i=0;i<G.vexnum;i++)
visited[i]=FALSE;
for(i=0,j=finished[G.vexnum-1];i<G.vexnum;i++,j=finished[G.vexnum-1-i])
if(!visited[j])
{
CSTree p;
p=(CSTree)malloc(sizeof(CSNode));
p->data=G.vertices[j].data;
p->firstchild=NULL;
p->nextsibling=NULL;
if(*T)
temp->nextsibling=p;
else
*T=p;
temp=p;
DGDFSTree(G,j,&p);
}
}
void DGDFSTree(OLGraph G,int v,CSTree *T)
{
visited[v]=TRUE;
printf("%c ",G.vertices[v].data);
CSTree temp;
temp=(CSTree)malloc(sizeof(CSNode));
Boolean first;
first=TRUE;
int i;
for(i=FirstAdjVex_Out(G,v);i>=0;i=NextAdjVex_Out(G,v,i))
if(!visited[i])
{
CSTree p;
p=(CSTree)malloc(sizeof(CSNode));
p->data=G.vertices[i].data;
p->firstchild=NULL;
p->nextsibling=NULL;
if(first)
{
first=FALSE;
(*T)->firstchild=p;
}
else
temp->nextsibling=p;
temp=p;
DGDFSTree(G,i,&p);
}
}
//孩子兄弟链表表示的树的遍历
void CSTreeTraverse(CSTree T)
{
if(T)
{
printf("%c ",T->data);
printf("%c的兄弟:",T->data);
CSTreeTraverse(T->nextsibling);
printf("\n%c孩子:",T->data);
CSTreeTraverse(T->firstchild);
}
}
有向图的强连通分量---Kosaraju算法
最新推荐文章于 2022-02-04 17:53:54 发布