有向图的强连通分量---Kosaraju算法

//有向图的强连通分量:利用深度优先搜索求有向图的强连通分量
//------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);
    }
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值