1. 深度優先搜索介紹
圖的深度優先搜索(Depth First Search),和樹的先序遍歷比較類似。
它的思想:假設初始狀態是圖中所有頂點均未被訪問,則從某個頂點v出發,首先訪問該頂點,然后依次從它的各個未被訪問的鄰接點出發深度優先搜索遍歷圖,直至圖中所有和v有路徑相通的頂點都被訪問到。 若此時尚有其他頂點未被訪問到,則另選一個未被訪問的頂點作起始點,重復上述過程,直至圖中所有頂點都被訪問到為止。
顯然,深度優先搜索是一個遞歸的過程。
2. 深度優先搜索圖解
2.1 無向圖的深度優先搜索
下面以"無向圖"為例,來對深度優先搜索進行演示。
對上面的圖G1進行深度優先遍歷,從頂點A開始。
第1步:訪問A。
第2步:訪問(A的鄰接點)C。
在第1步訪問A之后,接下來應該訪問的是A的鄰接點,即"C,D,F"中的一個。但在本文的實現中,頂點ABCDEFG是按照順序存儲,C在"D和F"的前面,因此,先訪問C。
第3步:訪問(C的鄰接點)B。
在第2步訪問C之后,接下來應該訪問C的鄰接點,即"B和D"中一個(A已經被訪問過,就不算在內)。而由於B在D之前,先訪問B。
第4步:訪問(C的鄰接點)D。
在第3步訪問了C的鄰接點B之后,B沒有未被訪問的鄰接點;因此,返回到訪問C的另一個鄰接點D。
第5步:訪問(A的鄰接點)F。
前面已經訪問了A,並且訪問完了"A的鄰接點B的所有鄰接點(包括遞歸的鄰接點在內)";因此,此時返回到訪問A的另一個鄰接點F。
第6步:訪問(F的鄰接點)G。
第7步:訪問(G的鄰接點)E。
因此訪問順序是:A -> C -> B -> D -> F -> G -> E
2.2 有向圖的深度優先搜索
下面以"有向圖"為例,來對深度優先搜索進行演示。
對上面的圖G2進行深度優先遍歷,從頂點A開始。
第1步:訪問A。
第2步:訪問B。
在訪問了A之后,接下來應該訪問的是A的出邊的另一個頂點,即頂點B。
第3步:訪問C。
在訪問了B之后,接下來應該訪問的是B的出邊的另一個頂點,即頂點C,E,F。在本文實現的圖中,頂點ABCDEFG按照順序存儲,因此先訪問C。
第4步:訪問E。
接下來訪問C的出邊的另一個頂點,即頂點E。
第5步:訪問D。
接下來訪問E的出邊的另一個頂點,即頂點B,D。頂點B已經被訪問過,因此訪問頂點D。
第6步:訪問F。
接下應該回溯"訪問A的出邊的另一個頂點F"。
第7步:訪問G。
因此訪問順序是:A -> B -> C -> E -> D -> F -> G
無向圖的鄰接矩陣實現代碼:
#include<stdio.h> #include<stdlib.h> #include<malloc.h> #include<string.h> #define MAX 100 typedef struct graph { char vexs[MAX]; int vexnum; int edgnum; int matrix[MAX][MAX]; }Graph,*PGraph; static int get_position(Graph g,char ch) { int i; for(i=0;i<g.vexnum;i++) if(g.vexs[i]==ch) return i; return -1; } Graph* create_graph() { char vexs[]={'A','B','C','D','E','F','G'}; char edges[][2]={{'A','C'},{'A','D'},{'A','F'},{'B','C'},{'C','D'},{'E','G'},{'F','G'}}; int vlen=sizeof(vexs)/sizeof(vexs[0]); int elen=sizeof(edges)/sizeof(edges[0]); int i,p1,p2; Graph *pG; if((pG=(Graph*)malloc(sizeof(Graph)))==NULL) return NULL; memset(pG,0,sizeof(Graph)); pG->vexnum=vlen; pG->edgnum=elen; for(i=0;i<pG->vexnum;i++) { pG->vexs[i]=vexs[i]; } for(i=0;i<pG->edgnum;i++) { p1=get_position(*pG,edges[i][0]); p2=get_position(*pG,edges[i][1]); pG->matrix[p1][p2]=1; pG->matrix[p2][p1]=1; } return pG; } void print_graph(Graph G) { int i,j; printf("matrix Graph:\n"); for(i=0;i<G.vexnum;i++) { for(j=0;j<G.vexnum;j++) printf("%d ",G.matrix[i][j]); printf("\n"); } } int first_vertex(Graph G,int v) { int i; for(i=0;i<G.vexnum;i++) if(G.matrix[v][i]==1) return i; return -1; } int next_vertex(Graph G,int v,int w) { int i; for(i=w+1;i<G.vexnum;i++) if(G.matrix[v][i]==1) return i; return -1; } void DFS(Graph G,int i,int *visited) { visited[i]=1; int w; printf("%c ",G.vexs[i]); for(w=first_vertex(G,i);w>=0;w=next_vertex(G,i,w)) { if(visited[w]==0) DFS(G,w,visited); } } void DFSTraverse(Graph G) { int i; int visited[MAX]; memset(visited,0,sizeof(visited)); printf("DFS : \n"); for(i=0;i<G.vexnum;i++) if(!visited[i]) DFS(G,i,visited); printf("\n"); } int main() { Graph *pG; pG=create_graph(); print_graph(*pG); printf("\n"); DFSTraverse(*pG); }
運行結果:
無向圖的鄰接表實現代碼:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<malloc.h> #define MAX 100 typedef struct ENode { int ivex; struct ENode *next_edge; }ENode; typedef struct VNode { char data; ENode *first_edge; }VNode; typedef struct LGraph { int vexnum; int edgnum; VNode vexs[MAX]; } LGraph; static int get_position(LGraph g,char ch) { int i; for(i=0;i<g.vexnum;i++) if(g.vexs[i].data==ch) return i; return -1; } LGraph* create_lgraph() { char c1,c2; char vexs[]= {'A','B','C','D','E','F','G'}; char edges[][2]= {{'A','C'},{'A','D'},{'A','F'},{'B','C'},{'C','D'},{'E','G'},{'F','G'}}; int vlen=sizeof(vexs)/sizeof(vexs[0]); int elen=sizeof(edges)/sizeof(edges[0]); int i,p1,p2; ENode *node1,*node2; LGraph *pG; if((pG=(LGraph*)malloc(sizeof(LGraph)))==NULL) return NULL; memset(pG,0,sizeof(LGraph)); pG->vexnum=vlen; pG->edgnum=elen; for(i=0;i<pG->vexnum;i++) { pG->vexs[i].data=vexs[i]; pG->vexs[i].first_edge=NULL; } for(i=0;i<pG->edgnum;i++) { c1=edges[i][0]; c2=edges[i][1]; p1=get_position(*pG,c1); p2=get_position(*pG,c2); node1=(ENode*)malloc(sizeof(ENode)); node1->ivex=p2; node1->next_edge=NULL; if(pG->vexs[p1].first_edge==NULL) pG->vexs[p1].first_edge=node1; else { ENode *tmp=pG->vexs[p1].first_edge; while(tmp->next_edge) { tmp=tmp->next_edge; } tmp->next_edge=node1; } node2=(ENode*)malloc(sizeof(ENode)); node2->ivex=p1; node2->next_edge=NULL; if(pG->vexs[p2].first_edge==NULL) pG->vexs[p2].first_edge=node2; else { ENode *tmp=pG->vexs[p2].first_edge; while(tmp->next_edge) { tmp=tmp->next_edge; } tmp->next_edge=node2; } } return pG; } void print_lgraph(LGraph G) { int i; ENode *node; printf("list Graph:\n"); for(i=0;i<G.vexnum;i++) { printf("%d(%c): ",i,G.vexs[i].data); node=G.vexs[i].first_edge; while(node) { printf("%d(%c) ",node->ivex,G.vexs[node->ivex].data); node=node->next_edge; } printf("\n"); } printf("\n"); } int main() { LGraph *pG; pG=create_lgraph(); print_lgraph(*pG); }
運行結果:
有向圖與無向圖的DFS一樣,只是創建圖的方式不一樣。