首先介绍概念问题,在有向图中,若 顶点v1 到 v2 存成路径,并且 v2 到 v1 存成 路径,则称 顶点 v1 和 v2 是强连通的。若 有向图 任意两个节点 都是 强连通的,则 称为强连通图。非强连通图的 极大强连通子图,为 强连通分量。
特别说明,连通的概念 属于 无向图,强连通 属于 有向图。例如:无向图:连通图,连通分量,生成树; 有向图:强连通图,强连通分量。
数据结构书上 简单的 说了 一个 求 强连通 分量的 一个 办法,详细如下:
其实 自己 不太明白 这个算法的原理。 好在 实现 这个算法没什么问题。
除了这个方法 还有其他 三种 方法:Kosaraju,Tarjan和Gabow。以后 有空 都实现一下。
完整源代码:
源代码工程文件网盘地址:点击打开链接
// CrossLinkGraph.cpp : 定义控制台应用程序的入口点。 //有向图的十字链表表示法 #include "stdafx.h" #include <cstdlib> #define MAX_VEX_NUM 20 enum E_State { E_State_Error = 0, E_State_Ok = 1, }; struct ArcNode//弧节点 { int tailIndex;//弧尾位置 int headIndex;//弧头位置 ArcNode * tailNext;//下一个弧尾相同的弧 ArcNode * headNext;//下一个弧头相同的弧 }; typedef struct VNode { char vexName;//顶点名称 ArcNode * firstIn; ArcNode * firstOut; }GraphList[MAX_VEX_NUM];// struct Graph { GraphList list;//顶点数组. int vexNum,arcNum; }; //获取弧 的 头节点 ArcNode * getHeadNode(){ ArcNode * pNode = (ArcNode *)malloc(sizeof(ArcNode)); if (pNode){ pNode->headIndex = pNode->tailIndex = -1; pNode->headNext = pNode->tailNext = NULL; } return pNode; } ArcNode * getArcNode(int tailIndex,int headIndex){ ArcNode * pNode = getHeadNode(); if (pNode){ pNode->headIndex = headIndex; pNode->tailIndex = tailIndex; } return pNode; } int vexLocation(Graph g,char vex){ for (int i = 0; i < g.vexNum; i++){ if (g.list[i].vexName == vex){ return i; } } return -1; } void createGrahp(Graph * g){ printf("输入图的顶点数 和 边(弧)数\n"); scanf("%d%d%*c",&g->vexNum,&g->arcNum); //构造顶点集 printf("请输入顶点集\n"); for (int i = 0; i < g->vexNum; i++){ char name; scanf("%c",&name); g->list[i].vexName = name; g->list[i].firstIn = g->list[i].firstOut = getHeadNode();//建立 头节点,并让头指针指向头节点 } //构造顶点关系 fflush(stdin); printf("请输入顶点的关系\n"); for (int i = 0; i < g->arcNum; i++){ char vex1,vex2; scanf("%c%c%*c",&vex1,&vex2); int location1 = vexLocation(*g,vex1); int location2 = vexLocation(*g,vex2); ArcNode * pNode = getArcNode(location1,location2); pNode->tailNext = g->list[location1].firstOut->tailNext; g->list[location1].firstOut->tailNext = pNode; pNode->headNext = g->list[location2].firstIn->headNext; g->list[location2].firstIn->headNext = pNode; } } //只要删除所有顶点的弧尾(或者弧头)节点即可, //同时删除弧头弧尾 ,内存错误 void destoryGraph(Graph * g){ for (int i = 0; i < g->vexNum; i++){ ArcNode * next = g->list[i].firstOut;//删除所有弧尾 while (next != NULL){ ArcNode * freeNode = next; next = next->tailNext; free(freeNode); } g->list[i].firstIn = g->list[i].firstOut = NULL; g->list[i].vexName = ' '; g->vexNum = g->arcNum = 0; } } int firstOutAdj(Graph g,int location){ ArcNode * next = g.list[location].firstOut->tailNext; if (next != NULL) { return next->headIndex; } return -1; } int nextOutAdj(Graph g,int location1,int location2){ ArcNode * next = g.list[location1].firstOut->tailNext; while (next != NULL){//查找到 vex2 if (next->headIndex == location2){ next = next->tailNext; break; } next = next->tailNext; } if (next != NULL){ return next->headIndex; } return -1; } int firstInAdj(Graph g,int location){ ArcNode * next = g.list[location].firstIn->headNext; if (next != NULL) { return next->tailIndex; } return -1; } int nextInAdj(Graph g,int location1,int location2){ ArcNode * next = g.list[location1].firstIn->headNext; while (next != NULL){//查找到 vex2 if (next->tailIndex == location2){ next = next->headNext; break; } next = next->headNext; } if (next != NULL){ return next->tailIndex; } return -1; } void outDfs(Graph g,int i,bool * isVisited,int * finished,int * count){ isVisited[i] = true; for (int next = firstOutAdj(g,i);next != -1; next = nextOutAdj(g,i,next)){ if (isVisited[next] == false){ outDfs(g,next,isVisited,finished,count); } } finished[(*count)++] = i;//将完成所有邻接点搜索的节点加入到数组中去. } void outDfsTraver(Graph g,int * finished){//以弧尾为导向的深度优先遍历 bool isVisited[MAX_VEX_NUM] = {false};//标记数组. int count = 0; for (int i = 0; i < g.vexNum; i++){ if (isVisited[i] == false){ outDfs(g,i,isVisited,finished,&count); } } } void inDfs(Graph g,int i,bool * isVisited){ printf("%c",g.list[i].vexName); isVisited[i] = true; for (int next = firstInAdj(g,i);next != -1; next = nextInAdj(g,i,next)){ if (isVisited[next] == false){ inDfs(g,next,isVisited); } } } //强连通图 void scc(Graph g){// bool isVisited[MAX_VEX_NUM] = {false};//标记数组. int finished[MAX_VEX_NUM] = {-1};//完成搜索 数组. outDfsTraver(g,finished);//按照搜索完成的先后关系,存入finished数组. int times = 0;//记录强连通分量的个数. for (int i = g.vexNum-1; i >= 0; i--){ int next = finished[i]; if (isVisited[next] == false){ printf("第%d个强连通分量为:",times); inDfs(g,next,isVisited); printf("\n"); times++; } } } void printGrahp(Graph g){ for (int i = 0; i < g.vexNum; i++){ printf("以%c为弧尾的 顶点有:",g.list[i].vexName); ArcNode * next = g.list[i].firstOut->tailNext;//删除所有弧尾 while (next != NULL){ printf("%c",g.list[next->headIndex].vexName); next = next->tailNext; } printf("\n以%c为弧头的 顶点有:",g.list[i].vexName); next = g.list[i].firstIn->headNext;//删除所有弧尾 while (next != NULL){ printf("%c",g.list[next->tailIndex].vexName); next = next->headNext; } printf("\n"); } } int _tmain(int argc, _TCHAR* argv[]) { Graph g; createGrahp(&g); printGrahp(g); printf("图的顶点数:%d,边(弧)树为:%d\n",g.vexNum,g.arcNum); scc(g);//找出有向图的强连通分量。。 destoryGraph(&g); return 0; }运行截图:
原文地址:http://blog.csdn.net/fuming0210sc/article/details/45008899