1. 程式人生 > >圖->連通性->有向圖的強連通分量

圖->連通性->有向圖的強連通分量

 

 文字描述

  有向圖強連通分量的定義:在有向圖G中,如果兩個頂點vi,vj間(vi>vj)有一條從vi到vj的有向路徑,同時還有一條從vj到vi的有向路徑,則稱兩個頂點強連通(strongly connected)。如果有向圖G的每兩個頂點都強連通,稱G是一個強連通圖。有向圖的極大強連通子圖,稱為強連通分量(strongly connected components)。

  用深度優先搜尋求有向圖的強連通分量的方法如下並假設有向圖的儲存結構為十字連結串列。

  1 在有向圖G上,從某個定點出發沿以該頂點為尾的弧進行深度優先遍歷;並按其所有鄰接點的搜尋都完成(即退出DFS函式)的順序將頂點排列起來。此時需對之前的深度優先遍歷演算法(見

圖遍歷)作兩處修改: (a)在進入DSFTraverse函式時首先進行計數變數的初始化,即在入口處加上count=0;(b)在退出DFS函式之前將完成搜尋的頂點號記錄在另一個輔助陣列finished[vexnum]中,即在DFS函式結束之前加上finished[count++]=v;

  2 在有向圖G上,從最後完成搜尋的頂點(即finished[count-1])出發,沿著以該頂點為頭的弧作逆向的深度優先搜尋遍歷,若遍歷不能訪問到有向圖中所有頂點,則從餘下的頂點中最後完搜尋的那個頂點出發,繼續作逆向的深度優先搜尋便利。依次類推。

  由此,每一次呼叫DFS作逆向深度優先遍歷所訪問到的頂點集便是有向圖G中一個強連通分量的頂點集。

 

示意圖

見本章後面的程式碼執行Example01, Example02, Example03, Example04。

 

演算法分析

求有向圖的強連通分量的演算法時間複雜度和深度優先搜尋遍歷相同。

 

程式碼實現

 

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #define    MAX_VERTEX_NUM    20
  5 #define    DEBUG
  6
#ifdef DEBUG 7 #include <stdarg.h> 8 #define LOG(args...) _log_(__FILE__, __FUNCTION__, __LINE__, ##args); 9 void _log_(const char *file, const char *function, int line, const char * format, ...) 10 { 11 char buf[1024] = {0}; 12 va_list list; 13 va_start(list, format); 14 sprintf(buf, "[%s,%s,%d]", file, function, line); 15 vsprintf(buf+strlen(buf), format, list); 16 sprintf(buf+strlen(buf), "\n"); 17 va_end(list); 18 printf(buf); 19 } 20 #else 21 #define LOG 22 #endif // DEBUG 23 24 ////////////////////////////////////////////////////////////// 25 // 十字連結串列作為圖的儲存結構 26 ////////////////////////////////////////////////////////////// 27 typedef enum {DG, DN, UDG, UDN} GraphKind; 28 typedef char InfoType; 29 typedef char VertexType; 30 typedef struct ArcBox{ 31 int tailvex, headvex; 32 struct ArcBox *hlink, *tlink; 33 InfoType *info; 34 }ArcBox; 35 typedef struct VexNode{ 36 VertexType data; 37 ArcBox *firstin, *firstout; 38 }VexNode; 39 typedef struct{ 40 VexNode xlist[MAX_VERTEX_NUM]; 41 int vexnum, arcnum; 42 GraphKind kind; 43 }OLGraph; 44 45 ////////////////////////////////////////////////////////////// 46 // 若G中存在頂點u,則返回該頂點在圖中位置;否則返回-1。 47 ////////////////////////////////////////////////////////////// 48 int LocateVex(OLGraph G, VertexType v) 49 { 50 int i = 0; 51 for(i=0; i<G.vexnum; i++) 52 { 53 if(G.xlist[i].data == v) 54 return i; 55 } 56 return -1; 57 } 58 59 ////////////////////////////////////////////////////////////// 60 // 若G中存在頂點位置loc存在,則返回其頂點名稱 61 ////////////////////////////////////////////////////////////// 62 VertexType LocateVInfo(OLGraph G, int loc) 63 { 64 return G.xlist[loc].data; 65 } 66 67 68 ////////////////////////////////////////////////////////////// 69 // 以十字連結串列作為圖的儲存結構建立有向圖 70 ////////////////////////////////////////////////////////////// 71 int CreateDG(OLGraph *G) 72 { 73 printf("\n以十字連結串列作為圖的儲存結構建立有向圖:\n"); 74 int i = 0, j = 0, k = 0, IncInfo = 0; 75 int v1 = 0, v2 = 0; 76 char tmp[10] = {0}; 77 ArcBox *p = NULL; 78 printf("輸入頂點數,弧數,其他資訊標誌位: "); 79 scanf("%d,%d,%d", &G->vexnum, &G->arcnum, &IncInfo); 80 for(i=0; i<G->vexnum; i++) 81 { 82 //輸入頂點值 83 printf("輸入第%d個頂點: ", i+1); 84 memset(tmp, 0, sizeof(tmp)); 85 scanf("%s", tmp); 86 //初始化指標 87 G->xlist[i].data = tmp[0]; 88 G->xlist[i].firstin = NULL; 89 G->xlist[i].firstout = NULL; 90 } 91 //輸入各弧並構造十字連結串列 92 for(k=0; k<G->arcnum; k++) 93 { 94 printf("輸入第%d條弧(頂點1, 頂點2): ", k+1); 95 memset(tmp, 0, sizeof(tmp)); 96 scanf("%s", tmp); 97 sscanf(tmp, "%c,%c", &v1, &v2); 98 i = LocateVex(*G, v1); 99 j = LocateVex(*G, v2); 100 //對弧結點賦值 101 p = (ArcBox *) malloc(sizeof(ArcBox)); 102 p->tailvex = i; 103 p->headvex = j; 104 p->hlink = G->xlist[j].firstin; 105 p->tlink = G->xlist[i].firstout; 106 p->info = NULL; 107 //完成在入弧和出弧鏈頭的插入 108 G->xlist[j].firstin = p; 109 G->xlist[i].firstout = p; 110 //若弧有相關的資訊,則輸入 111 if(IncInfo) 112 { 113 //Input(p->info); 114 } 115 } 116 return 0; 117 } 118 119 int CreateGraph(OLGraph *G) 120 { 121 printf("輸入圖型別: +有向圖(0), -有向網(1), -無向圖(2), -無向網(3): "); 122 scanf("%d", &G->kind); 123 switch(G->kind){ 124 case DG: 125 return CreateDG(G); 126 case DN: 127 case UDN: 128 case UDG: 129 default: 130 printf("not support!\n"); 131 return -1; 132 } 133 return 0; 134 } 135 136 ////////////////////////////////////////////////////////////// 137 // 列印圖結點 138 ////////////////////////////////////////////////////////////// 139 void printG(OLGraph G) 140 { 141 printf("\n列印圖結點\n"); 142 if(G.kind == DG){ 143 printf("型別:有向圖;頂點數 %d, 弧數 %d\n", G.vexnum, G.arcnum); 144 }else if(G.kind == DN){ 145 printf("型別:有向網;頂點數 %d, 弧數 %d\n", G.vexnum, G.arcnum); 146 }else if(G.kind == UDG){ 147 printf("型別:無向圖;頂點數 %d, 弧數 %d\n", G.vexnum, G.arcnum); 148 }else if(G.kind == UDN){ 149 printf("型別:無向網;頂點數 %d, 弧數 %d\n", G.vexnum, G.arcnum); 150 } 151 int i = 0; 152 ArcBox *fi = NULL; 153 ArcBox *fo = NULL; 154 for(i=0; i<G.vexnum; i++) 155 { 156 printf("%c: ", G.xlist[i].data); 157 fi = G.xlist[i].firstin; 158 fo = G.xlist[i].firstout; 159 printf("{hlink="); 160 while(fi) 161 { 162 printf("(%d,%c)->(%d,%c); ", fi->tailvex, LocateVInfo(G, fi->tailvex), fi->headvex, LocateVInfo(G, fi->headvex)); 163 fi = fi->hlink; 164 } 165 printf("} {tlink="); 166 while(fo) 167 { 168 printf("(%d,%c)->(%d,%c); ", fo->tailvex, LocateVInfo(G, fo->tailvex), fo->headvex, LocateVInfo(G, fo->headvex)); 169 fo = fo->tlink; 170 } 171 printf("}\n"); 172 } 173 return ; 174 } 175 176 177 178 ////////////////////////////////////////////////////////////// 179 // 用雙向遍歷的方法求有向圖的強連通分量 180 ////////////////////////////////////////////////////////////// 181 int GVisited[MAX_VERTEX_NUM] = {0}; 182 void (*visitfun)(OLGraph G, int v); 183 184 //記錄退出DFS函式之前完成搜尋的頂點號 185 int GFinished[MAX_VERTEX_NUM] = {0}; 186 int GCount = 0; 187 188 #define D_OUT 0 189 #define D_IN 1 190 typedef enum DIRECTION 191 { 192 IN, 193 OUT 194 }DIRECTION; 195 196 ////////////////////////////////////////////////////////////// 197 // 列印結點在圖中的位置及結點資訊 198 ////////////////////////////////////////////////////////////// 199 void printvex(OLGraph G, int v) 200 { 201 printf("[%d]:%c\t", v, G.xlist[v].data); 202 return ; 203 } 204 205 ////////////////////////////////////////////////////////////// 206 // direction is IN: 返回圖G中以頂點位置為V的頂點為入度的第一個結點 207 // direction is OUT: 返回圖G中以頂點位置為V的頂點為出度的第一個結點 208 ////////////////////////////////////////////////////////////// 209 int FirstAdjVex(OLGraph G, int v, int direction) 210 { 211 if(direction == IN){ 212 return (G.xlist[v].firstin)?G.xlist[v].firstin->tailvex:-1; 213 }else if(direction == OUT){ 214 return (G.xlist[v].firstout)?G.xlist[v].firstout->headvex:-1; 215 }else{ 216 return -1; 217 } 218 } 219 220 ////////////////////////////////////////////////////////////// 221 // direction is IN: G中位置w是以v為入度的結點, 返回下一個以v為入度的結點 222 // direction is OUT: G中位置w是以v為出度的結點, 返回下一個以v為出度的結點 223 ////////////////////////////////////////////////////////////// 224 int NextAdjVex(OLGraph G, int v, int w, int direction) 225 { 226 int ret = -1; 227 if(direction == IN){ 228 ArcBox *fi = NULL; 229 fi = G.xlist[v].firstin; 230 while(fi) 231 { 232 if(fi->tailvex == w) 233 break; 234 fi = fi->hlink; 235 } 236 if(fi && (fi=fi->hlink)){ 237 ret = fi->tailvex; 238 }else{ 239 ret = -1; 240 } 241 }else if(direction == OUT){ 242 ArcBox *fo = NULL; 243 fo = G.xlist[v].firstout; 244 while(fo) 245 { 246 if(fo->headvex == w) 247 break; 248 fo = fo->tlink; 249 } 250 if(fo && (fo=fo->tlink)){ 251 ret = fo->headvex; 252 }else{ 253 ret = -1; 254 } 255 } 256 return ret; 257 } 258 ////////////////////////////////////////////////////////////// 259 // direction is IN :從第v個頂點出發, 沿著以v為入度的頂點的方式, 遞迴地深度優先遍歷圖G 260 // direction is OUT :從第v個頂點出發, 沿著以v為出度的頂點的方式, 遞迴地深度優先遍歷圖G 261 ////////////////////////////////////////////////////////////// 262 void DFS(OLGraph G, int v, int direction) 263 { 264 GVisited[v] = 1; 265 printvex(G, v); 266 int w = 0; 267 for(w=FirstAdjVex(G,v,direction); w>=0; w=NextAdjVex(G, v, w, direction)) 268 { 269 if(!GVisited[w]){ 270 DFS(G, w, direction); 271 } 272 } 273 GFinished[GCount++] = v; 274 } 275 276 ////////////////////////////////////////////////////////////// 277 // 1 從第一個出發,對圖G作深度優先遍歷並記錄下退出DFS函式的順序 278 // 2 從最後一個退出DFS函式的頂點出發, 反方向對圖G作深度優先遍歷並求出圖的強連通分量 279 ////////////////////////////////////////////////////////////// 280 void DFSTraverse(OLGraph G, void (*visitfun)(OLGraph G, int v)) 281 { 282 visitfun = printvex; 283 int v = 0; 284 int index = 0; 285 286 printf("\n深度優先搜尋(以第一個頂點為尾的弧進行深度優先搜尋遍歷):\n"); 287 //訪問標誌陣列初始化 288 for(v=0; v<G.vexnum; v++) 289 { 290 GVisited[v] = 0; 291 GFinished[v] = 0; 292 } 293 GCount = 0; 294 295 for(v=0; v<G.vexnum; v++) 296 { 297 if(!GVisited[v]){ 298 DFS(G, v, OUT); 299 } 300 } 301 302 printf("\n退出DFS函式的次序location和頂點位置index為:\n"); 303 for(v=0; v<GCount; v++) 304 { 305 printf("[location:%d, index:%d] ", v, GFinished[v]); 306 } 307 printf("\n"); 308 309 printf("深度優先搜尋(從最後完成搜尋的頂點出發,沿著以該頂點為頭的弧作逆向的深度優先搜尋遍歷):"); 310 //訪問標誌陣列初始化 311 for(v=0; v<G.vexnum; v++) 312 { 313 GVisited[v] = 0; 314 } 315 for(v=0; v<GCount; v++) 316 { 317 index = GFinished[GCount-1-v]; 318 if(!GVisited[index]){ 319 printf("\n強連通分量:"); 320 DFS(G, index, IN); 321 } 322 } 323 printf("\n"); 324 } 325 326 327 int main(int argc, char *argv[]) 328 { 329 OLGraph G; 330 if(CreateGraph(&G) > -1){ 331 printG(G); 332 } 333 DFSTraverse(G, printvex); 334 }
有向圖(十字連結串列儲存)的強連通分量

 

程式碼執行

Example01

 

 

[[email protected] Data.Structure]$ ./a.out 
輸入圖型別: +有向圖(0), -有向網(1), -無向圖(2), -無向網(3): 0

以十字連結串列作為圖的儲存結構建立有向圖:
輸入頂點數,弧數,其他資訊標誌位: 4,7,0
輸入第1個頂點: a
輸入第2個頂點: b
輸入第3個頂點: c
輸入第4個頂點: d
輸入第1條弧(頂點1, 頂點2): a,b
輸入第2條弧(頂點1, 頂點2): a,c
輸入第3條弧(頂點1, 頂點2): c,a
輸入第4條弧(頂點1, 頂點2): c,d
輸入第5條弧(頂點1, 頂點2): d,c
輸入第6條弧(頂點1, 頂點2): d,a
輸入第7條弧(頂點1, 頂點2): d,b

列印圖結點
型別:有向圖;頂點數 4, 弧數 7
a: {hlink=(3,d)->(0,a); (2,c)->(0,a); }        {tlink=(0,a)->(2,c); (0,a)->(1,b); }
b: {hlink=(3,d)->(1,b); (0,a)->(1,b); }        {tlink=}
c: {hlink=(3,d)->(2,c); (0,a)->(2,c); }        {tlink=(2,c)->(3,d); (2,c)->(0,a); }
d: {hlink=(2,c)->(3,d); }        {tlink=(3,d)->(1,b); (3,d)->(0,a); (3,d)->(2,c); }

深度優先搜尋(以第一個頂點為尾的弧進行深度優先搜尋遍歷):
[0]:a    [2]:c    [3]:d    [1]:b    
退出DFS函式的次序location和頂點位置index為:
[location:0, index:1] [location:1, index:3] [location:2, index:2] [location:3, index:0] 
深度優先搜尋(從最後完成搜尋的頂點出發,沿著以該頂點為頭的弧作逆向的深度優先搜尋遍歷):
強連通分量:[0]:a    [3]:d    [2]:c    
強連通分量:[1]:b    
[[email protected] Data.Structure]$ 
Example01

 

Example02

 

 

[[email protected] blogs]$ ./a.out 
輸入圖型別: +有向圖(0), -有向網(1), -無向圖(2), -無向網(3): 0

以十字連結串列作為圖的儲存結構建立有向圖:
輸入頂點數,弧數,其他資訊標誌位: 6,8,0
輸入第1個頂點: 1
輸入第2個頂點: 2
輸入第3個頂點: 3
輸入第4個頂點: 4
輸入第5個頂點: 5
輸入第6個頂點: 6
輸入第1條弧(頂點1, 頂點2): 1,2
輸入第2條弧(頂點1, 頂點2): 1,3
輸入第3條弧(頂點1, 頂點2): 2,4
輸入第4條弧(頂點1, 頂點2): 3,4
輸入第5條弧(頂點1, 頂點2): 3,5
輸入第6條弧(頂點1, 頂點2): 4,1
輸入第7條弧(頂點1, 頂點2): 4,7
輸入第8條弧(頂點1, 頂點2): 5,6

列印圖結點
型別:有向圖;頂點數 6, 弧數 8
1: {hlink=(3,4)->(0,1); }        {tlink=(0,1)->(2,3); (0,1)->(1,2); }
2: {hlink=(0,1)->(1,2); }        {tlink=(1,2)->(3,4); }
3: {hlink=(0,1)->(2,3); }        {tlink=(2,3)->(4,5); (2,3)->(3,4); }
4: {hlink=(2,3)->(3,4); (1,2)->(3,4); }        {tlink=(3,4)->(-1,<); (3,4)->(0,1); }
5: {hlink=(2,3)->(4,5); }        {tlink=(4,5)->(5,6); }
6: {hlink=(4,5)->(5,6); }        {tlink=}

深度優先搜尋(以第一個頂點為尾的弧進行深度優先搜尋遍歷):
[0]:1    [2]:3    [4]:5    [5]:6    [3]:4    [1]:2    
退出DFS函式的次序location和頂點位置index為:
[location:0, index:5] [location:1, index:4] [location:2, index:3] [location:3, index:2] [location:4, index:1] [location:5, index:0] 
深度優先搜尋(從最後完成搜尋的頂點出發,沿著以該頂點為頭的弧作逆向的深度優先搜尋遍歷):
強連通分量:[0]:1    [3]:4    [2]:3    [1]:2    
強連通分量:[4]:5    
強連通分量:[5]:6    
[[email protected] blogs]$ 
Example02

 

 

Example03

 

[[email protected] blogs]$ ./a.out 
輸入圖型別: +有向圖(0), -有向網(1), -無向圖(2), -無向網(3): 0

以十字連結串列作為圖的儲存結構建立有向圖:
輸入頂點數,弧數,其他資訊標誌位: 8,13,0
輸入第1個頂點: a
輸入第2個頂點: b
輸入第3個頂點: c
輸入第4個頂點: d
輸入第5個頂點: e
輸入第6個頂點: f
輸入第7個頂點: g
輸入第8個頂點: h
輸入第1條弧(頂點1, 頂點2): a,b
輸入第2條弧(頂點1, 頂點2): b,c
輸入第3條弧(頂點1, 頂點2): d,c
輸入第4條弧(頂點1, 頂點2): c,d
輸入第5條弧(頂點1, 頂點2): e,a
輸入第6條弧(頂點1, 頂點2): b,e
輸入第7條弧(頂點1, 頂點2): b,f
輸入第8條弧(頂點1, 頂點2): c,g
輸入第9條弧(頂點1, 頂點2): h,d
輸入第10條弧(頂點1, 頂點2): e,f
輸入第11條弧(頂點1, 頂點2): g,f
輸入第12條弧(頂點1, 頂點2): f,g
輸入第13條弧(頂點1, 頂點2): h,g

列印圖結點
型別:有向圖;頂點數 8, 弧數 13
a: {hlink=(4,e)->(0,a); }        {tlink=(0,a)->(1,b); }
b: {hlink=(0,a)->(1,b); }        {tlink=(1,b)->(5,f); (1,b)->(4,e); (1,b)->(2,c); }
c: {hlink=(3,d)->(2,c); (1,b)->(2,c); }        {tlink=(2,c)->(6,g); (2,c)->(3,d); }
d: {hlink=(7,h)->(3,d); (2,c)->(3,d); }        {tlink=(3,d)->(2,c); }
e: {hlink=(1,b)->(4,e); }        {tlink=(4,e)->(5,f); (4,e)->(0,a); }
f: {hlink=(6,g)->(5,f); (4,e)->(5,f); (1,b)->(5,f); }        {tlink=(5,f)->(6,g); }
g: {hlink=(7,h)->(6,g); (5,f)->(6,g); (2,c)->(6,g); }        {tlink=(6,g)->(5,f); }
h: {hlink=}        {tlink=(7,h)->(6,g); (7,h)->(3,d); }

深度優先搜尋(以第一個頂點為尾的弧進行深度優先搜尋遍歷):
[0]:a    [1]:b    [5]:f    [6]:g    [4]:e    [2]:c    [3]:d    [7]:h    
退出DFS函式的次序location和頂點位置index為:
[location:0, index:6] [location:1, index:5] [location:2, index:4] [location:3, index:3] [location:4, index:2] [location:5, index:1] [location:6, index:0] [location:7, index:7] 
深度優先搜尋(從最後完成搜尋的頂點出發,沿著以該頂點為頭的弧作逆向的深度優先搜尋遍歷):
強連通分量:[7]:h    
強連通分量:[0]:a    [4]:e    [1]:b    
強連通分量:[2]:c    [3]:d    
強連通分量:[5]:f    [6]:g    
[[email protected] blogs]$ 
Example03

 

 

Example04

 

[[email protected] blogs]$ ./a.out 
輸入圖型別: +有向圖(0), -有向網(1), -無向圖(2), -無向網(3): 0

以十字連結串列作為圖的儲存結構建立有向圖:
輸入頂點數,弧數,其他資訊標誌位: 10,15
輸入第1個頂點: ^C
[[email protected] blogs]$ ./a.out 
輸入圖型別: +有向圖(0), -有向網(1), -無向圖(2), -無向網(3): 0

以十字連結串列作為圖的儲存結構建立有向圖:
輸入頂點數,弧數,其他資訊標誌位: 10,15,0
輸入第1個頂點: 0
輸入第2個頂點: 1
輸入第3個頂點: 2
輸入第4個頂點: 3
輸入第5個頂點: 4
輸入第6個頂點: 5
輸入第7個頂點: 6
輸入第8個頂點: 7
輸入第9個頂點: 8
輸入第10個頂點: 9
輸入第1條弧(頂點1, 頂點2): 9,2
輸入第2條弧(頂點1, 頂點2): 7,9
輸入第3條弧(頂點1, 頂點2): 2,7
輸入第4條弧(頂點1, 頂點2): 2,1
輸入第5條弧(頂點1, 頂點2): 2,4
輸入第6條弧(頂點1, 頂點2): 7,4
輸入第7條弧(頂點1, 頂點2): 1,8
輸入第8條弧(頂點1, 頂點2): 0,1
輸入第9條弧(頂點1, 頂點2): 1,0
輸入第10條弧(頂點1, 頂點2): 0,4
輸入第11條弧(頂點1, 頂點2): 8,5
輸入第12條弧(頂點1, 頂點2): 5,0
輸入第13條弧(頂點1, 頂點2): 4,3
輸入第14條弧(頂點1, 頂點2): 3,4
輸入第15條弧(頂點1, 頂點2): 5,6

列印圖結點
型別:有向圖;頂點數 10, 弧數 15
0: {hlink=(5,5)->(0,0); (1,1)->(0,0); }        {tlink=(0,0)->(4,4); (0,0)->(1,1); }
1: {hlink=(0,0)->(1,1); (2,2)->(1,1); }        {tlink=(1,1)->(0,0); (1,1)->(8,8); }
2: {hlink=(9,9)->(2,2); }        {tlink=(2,2)->(4,4); (2,2)->(1,1); (2,2)->(7,7); }
3: {hlink=(4,4)->(3,3); }        {tlink=(3,3)->(4,4); }
4: {hlink=(3,3)->(4,4); (0,0)->(4,4); (7,7)->(4,4); (2,2)->(4,4); }        {tlink=(4,4)->(3,3); }
5: {hlink=(8,8)->(5,5); }        {tlink=(5,5)->(6,6); (5,5)->(0,0); }
6: {hlink=(5,5)->(6,6); }        {tlink=}
7: {hlink=(2,2)->(7,7); }        {tlink=(7,7)->(4,4); (7,7)->(9,9); }
8: {hlink=(1,1)->(8,8); }        {tlink=(8,8)->(5,5); }
9: {hlink=(7,7)->(9,9); }        {tlink=(9,9)->(2,2); }

深度優先搜尋(以第一個頂點為尾的弧進行深度優先搜尋遍歷):
[0]:0    [4]:4    [3]:3    [1]:1    [8]:8    [5]:5    [6]:6    [2]:2    [7]:7    [9]:9    
退出DFS函式的次序location和頂點位置index為:
[location:0, index:3] [location:1, index:4] [location:2, index:6] [location:3, index:5] [location:4, index:8] [location:5, index:1] [location:6, index:0] [location:7, index:9] [location:8, index:7] [location:9, index:2] 
深度優先搜尋(從最後完成搜尋的頂點出發,沿著以該頂點為頭的弧作逆向的深度優先搜尋遍歷):
強連通分量:[2]:2    [9]:9    [7]:7    
強連通分量:[0]:0    [5]:5    [8]:8    [1]:1    
強連通分量:[6]:6    
強連通分量:[4]:4    [3]:3    
[[email protected] blogs]$ 
Example04