圖的深度優先遍歷(遞迴與非遞迴演算法)和廣度優先遍歷
阿新 • • 發佈:2019-01-03
老師的題目::
實驗內容
已知某地區的公路網以圖表示,圖中的頂點表示站點,任意兩站點間的路段以帶權的邊構成的鄰接矩陣表示,矩陣中非零元表示兩個站點間存在直接的路段,否則沒有路段。
開啟E:\Test資料夾中的exp06.cpp檔案,補充編寫所需程式碼。程式首先進行圖的連通性判定,若圖連通則輸出連通訊息,否則繼續計算和輸出圖的連通分量數。
輸入資料在檔案exp06.in中,首行的整數是站點的總數n(1<n<=30);第2行開始的n行中,每行n個整數,是這n個站點構成的公路網的鄰接矩陣。例如,
6
01 3 4 9 0
10 9 9 0 0
39 0 0 6 8
49 0 0 5 7
90 6 5 0 4
00 8 7 4 0
主函式中,在呼叫讀入資料函式readData()時,會自動將矩陣中的零元(除對角線保持0以外)替換成無窮大(9999)。
Search(intv)函式實現從頂點v出發的一次搜尋過程,並累計訪問頂點數。
若圖是連通的,則輸出檔案exp06.out中包含如下文字:
All vertexsare connected.
否則,計算和輸出連通分量數,輸出檔案的內容則如下例:
The number of connected components is 2.
解題思路
利用一次深度優先或者廣度優先搜尋過程中對訪問頂點數的計數,並判斷其與圖的頂點總數是否相等來判定圖的連通性。
如果圖不連通,則繼續從下一個未被訪問的頂點出發再進行一次搜尋,如此反覆,直到已遍歷圖的所有頂點,累計的搜尋次數即是圖的連通分量數。
我在程式碼中都做了註解
#include <iostream> #include <stdio.h> using namespace std; const int Size=30; const double INF=9999; // infinity (無窮大) int vexnum; // total number of vertex (頂點總數) int adjmat[Size][Size]; // adjacent matrix (鄰接矩陣) int mark[Size]; // vector of visiting mark of vertex (頂點訪問標記向量) int visitnum; // number of visited vertex for one search (一次搜尋中被訪問頂點數) int adjnum; // number of connected components (連通分量數) void readData() { int i,j; cin>>vexnum; // input vexnum for(i=0; i<vexnum; i++) for(j=0; j<vexnum; j++) { cin>>adjmat[i][j]; if(i!=j && adjmat[i][j]==0) adjmat[i][j]=INF; } } /*int first_adj(int v){ int w; for(w=0;w<vexnum;w++) if(adjmat[v][w]!=INF||v!=w) return w; return -1; } int next_adj(int v,int w){ for(w+=1;w<vexnum;w++) if(adjmat[v][w]!=INF||v!=w) return w; return -1; }*/ void Search(int v) // one time search, v represents the starting vertex {//************************************************ //******************************************** /*int w=-1; //書上的解法,太麻煩了 mark[v]=1; visitnum++; w=first_adj(v); while(w!=-1){ if(!mark[w]) Search(w); w=next_adj(v,w); }*/ //============================================== //************************************************** /*遞迴的深度優先搜尋 int i; if(mark[v]==1) return; //訪問過了,要有,可用於判斷連通分量 mark[v]=1; //否則訪問他 visitnum++; for(i=0;i<vexnum;i++){ if(adjmat[v][i]!=INF&&v!=i&&mark[i]!=1) //找到未訪問過的鄰接點 Search(i); } return;*/ //==================================================== //*************************************************** /* //非遞迴的深度優先搜尋 int *stack=new int[vexnum],top=-1,w; if(mark[v]==1) return; stack[++top]=v; mark[v]=1; visitnum++; while(top!=-1){ v=stack[top]; //不能top--,因為後面還要用到此處節點 for(w=0;w<vexnum;w++){//找一個未訪問的鄰接點,可以使用上面的first_adj(v) if(adjmat[v][w]!=INF && v!=w && mark[w]!=1) break; } if(w==vexnum) top--; //此節點 沒有 還沒找過的鄰接點了,退棧 else{ //有未訪問鄰接點,人棧,接下來從這個節點繼續深度訪問 stack[++top]=w; mark[w]=1; visitnum++; } } */ //===================================================== //******************************************* /* //廣度優先搜尋 先訪問再入隊 int *queue=new int[vexnum+1],front=0,rear=0; int w; if(mark[v]==1) return; mark[v]=1; visitnum++; queue[rear++]=v; while(front!=rear){ v=queue[front++]; for(w=0;w<vexnum;w++){ //找到所有未訪問鄰接點入隊 if(adjmat[v][w]!=INF&&v!=w&&mark[w]!=1){ queue[rear++]=w; mark[w]=1; visitnum++; } } //找完了 } //======================================== */ //================================================ } int main() { int i; /* freopen("exp06.in", "r", stdin); freopen("exp06.out", "w", stdout);*/ readData(); // input data for(i=0; i<vexnum; i++) mark[i]=0; // initialze the visiting mark visitnum=0; Search(0); // one time search from vertex 0 if(visitnum==vexnum) cout<<"All vertexs are connected.\n"; else { adjnum=1; //************************************************ for(i=0;i<vexnum;i++){ if(!mark[i]){ Search(i); adjnum++; } } //================================================ cout<<"The number of connected components is "<<adjnum<<".\n"; } return 0; }