鄰接表實現--圖的深度優先遍歷DFS和廣度優先遍歷BFS
阿新 • • 發佈:2019-01-11
圖論中一個基本的概念就是遍歷。就是訪問到圖的每一個頂點,同時每個頂點只訪問一次。
DFS和BFS的概念和思路網上說明的很詳細了。但是網上很多程式碼實現有缺陷,基本都沒有考慮圖不連通的情況,比如某個頂點A和其它任何一個頂點都不關聯,那麼這個頂點A就訪問不到了。如果遍歷的起點剛好是孤立的頂點A,就只能訪問頂點A了,其它頂點就訪問不到了。
我這邊的程式碼就是增加了這些情況的處理,確保每個頂點都能可以訪問到。
完整的程式碼如下(通過鄰接表實現圖):
#define MAX_VERTEX 16 typedef enum { UNDIRECTED_GRAPH = 0, //無向圖 DIRECTED_GRAPH = 1, //有向圖 UNDIRECTED_NET = 2, //無向網 DIRECTED_NET = 3, //有向網 }GRAPH_TYPE; typedef struct _ARC_NODE { int index; //鄰接頂點在頂點陣列中的索引值 struct _ARC_NODE* next;//指向下一個相鄰頂點 }ARC_NODE,*PARC_NODE; typedef struct _VERTEX { char data;//頂點資料值 PARC_NODE outHead;//出邊表頭指標 PARC_NODE inHead; //入邊表頭指標 }VERTEX,*PVERTEX; typedef struct { GRAPH_TYPE type; //圖的型別 int vertexCount;//頂點個數 BOOL visitFlag[MAX_VERTEX]; VERTEX vertex[MAX_VERTEX]; }LINKED_GRAPH,*PLINKED_GRAPH; //鄰接表方式的圖或者網 void DFS(PLINKED_GRAPH graph,int startVertexIndex); void BFS(PLINKED_GRAPH graph,int startVertexIndex); void Visit(PLINKED_GRAPH graph,int vIndex) { graph->visitFlag[vIndex] = TRUE; //設定已訪問標誌 printf("Visit Vertex: %c\r\n",graph->vertex[vIndex].data); } void InitVistFlag(PLINKED_GRAPH graph) { for(int i=0;i<graph->vertexCount;i++) { graph->visitFlag[i] = FALSE; } } void DFS(PLINKED_GRAPH graph,int startVertexIndex) { stack<int> s; //訪問棧 s.push(startVertexIndex); while(!s.empty()) { int vertexIndex = s.top(); if(!graph->visitFlag[vertexIndex])//未訪問過 { Visit(graph,vertexIndex); } s.pop();//vertexIndex頂點出棧 //這裡我們通過出度表來遍歷 PARC_NODE p = graph->vertex[vertexIndex].outHead; while(p) { //與vertexIndex相鄰的頂點並且未訪問過的頂點全部入棧 if(!graph->visitFlag[p->index]) { s.push(p->index); } p = p->next;//指向下一個與vertexIndex相鄰的頂點 } } //圖並不一定是連通的,因此要確保每個頂點都遍歷過 for(int i=0;i<graph->vertexCount;i++) { if(!graph->visitFlag[i]) { printf("Not Connected vertex start DFS: %c\r\n",graph->vertex[i]); DFS(graph,i); } } } void BFS(PLINKED_GRAPH graph,int startVertexIndex) { queue<int> q; //訪問佇列 q.push(startVertexIndex);//起始訪問的頂點入隊 while(!q.empty()) { int vertexIndex = q.front(); if(!graph->visitFlag[vertexIndex])//未訪問過 { Visit(graph,vertexIndex); } q.pop();//vertexIndex頂點出隊 //這裡我們通過出度表來遍歷 PARC_NODE p = graph->vertex[vertexIndex].outHead; while(p) { //與vertexIndex相鄰的頂點並且未訪問過的頂點全部入隊 if(!graph->visitFlag[p->index]) { q.push(p->index); } p = p->next;//指向下一個與vertexIndex相鄰的頂點 } } //圖並不一定是連通的,因此要確保每個頂點都遍歷過 for(int i=0;i<graph->vertexCount;i++) { if(!graph->visitFlag[i]) { printf("Not Connected vertex start BFS: %c\r\n",graph->vertex[i]); BFS(graph,i); } } } void InitLinkedGraph(PLINKED_GRAPH graph) { graph->type = UNDIRECTED_GRAPH; //無向圖 graph->vertexCount = 10; for(int i=0;i<graph->vertexCount;i++) { graph->vertex[i].data = 'A'+i; //頂點為'A','B','C'等等 } graph->vertex[0].outHead = new ARC_NODE; graph->vertex[0].outHead->index = 1; //AB有邊 graph->vertex[0].outHead->next = new ARC_NODE; graph->vertex[0].outHead->next->index = 4;//AE有邊 graph->vertex[0].outHead->next->next = NULL; graph->vertex[1].outHead = new ARC_NODE; graph->vertex[1].outHead->index = 0; //BA有邊 graph->vertex[1].outHead->next = new ARC_NODE; graph->vertex[1].outHead->next->index = 3;//BD有邊 graph->vertex[1].outHead->next->next = NULL; graph->vertex[2].outHead = new ARC_NODE; graph->vertex[2].outHead->index = 4; //CE有邊 graph->vertex[2].outHead->next = new ARC_NODE; graph->vertex[2].outHead->next->index = 5;//CF有邊 graph->vertex[2].outHead->next->next = new ARC_NODE; graph->vertex[2].outHead->next->next->index = 6;//CG有邊 graph->vertex[2].outHead->next->next->next = new ARC_NODE; graph->vertex[2].outHead->next->next->next->index = 7; //CG有邊 graph->vertex[2].outHead->next->next->next->next = NULL; graph->vertex[3].outHead = new ARC_NODE; graph->vertex[3].outHead->index = 1; //DB有邊 graph->vertex[3].outHead->next = NULL; graph->vertex[4].outHead = new ARC_NODE; graph->vertex[4].outHead->index = 2; //EC有邊 graph->vertex[4].outHead->next = NULL; graph->vertex[5].outHead = new ARC_NODE; graph->vertex[5].outHead->index = 2; //FC有邊 graph->vertex[5].outHead->next = NULL; graph->vertex[6].outHead = new ARC_NODE; graph->vertex[6].outHead->index = 2; //GC有邊 graph->vertex[6].outHead->next = new ARC_NODE; graph->vertex[6].outHead->next->index = 8;//GI有邊 graph->vertex[6].outHead->next->next = new ARC_NODE; graph->vertex[6].outHead->next->next->index= 9;//GJ有邊 graph->vertex[6].outHead->next->next->next = NULL; graph->vertex[7].outHead = new ARC_NODE; graph->vertex[7].outHead->index = 2; //HC有邊 graph->vertex[7].outHead->next = NULL; graph->vertex[8].outHead = new ARC_NODE; graph->vertex[8].outHead->index = 6; //IG有邊 graph->vertex[8].outHead->next = NULL; graph->vertex[9].outHead = new ARC_NODE; graph->vertex[9].outHead->index = 6; //JG有邊 graph->vertex[9].outHead->next = NULL; } void PrintLinkedGraph(PLINKED_GRAPH graph) { printf("Linked Graph Info:\r\n"); for(int i=0;i<graph->vertexCount;i++) { printf("%2c",graph->vertex[i].data); PARC_NODE p = graph->vertex[i].outHead; while(p) { printf(" --> %2c",graph->vertex[p->index].data); p = p->next; } printf("\r\n"); } printf("\r\n"); } void DestroyLinkedGraph(PLINKED_GRAPH graph) { for(int i=0;i<graph->vertexCount;i++) { PARC_NODE p = graph->vertex[i].outHead; while(p) { PARC_NODE pNext = p->next; p->next = NULL; delete p; p = pNext; } } } void TestLinkedGraph() { LINKED_GRAPH graph = {UNDIRECTED_GRAPH,0}; InitLinkedGraph(&graph); InitVistFlag(&graph); PrintLinkedGraph(&graph); printf("Linked Graph DFS:\r\n"); DFS(&graph,0); printf("\r\n"); InitVistFlag(&graph); printf("Linked Graph DFS:\r\n"); BFS(&graph,0); printf("\r\n"); DestroyLinkedGraph(&graph); }