列出連通集(DFS及BFS遍歷圖) -- 數據結構
阿新 • • 發佈:2019-05-12
前序 理解 ali 同時 lang 實現 int all 鄰接矩陣
題目:
7-1 列出連通集 (30 分)給定一個有N個頂點和E條邊的無向圖,請用DFS和BFS分別列出其所有的連通集。假設頂點從0到N−1編號。進行搜索時,假設我們總是從編號最小的頂點出發,按編號遞增的順序訪問鄰接點。
輸入格式:
輸入第1行給出2個整數N(0<N≤10)和E,分別是圖的頂點數和邊數。隨後E行,每行給出一條邊的兩個端點。每行中的數字之間用1空格分隔。
輸出格式:
按照"{ v?1?? v?2?? ... v?k?? }"的格式,每行輸出一個連通集。先輸出DFS的結果,再輸出BFS的結果。
輸入樣例:
8 6 0 7 0 1 2 0 4 1 2 4 3 5
輸出樣例:
{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }
分析:
當讀完這道題之後,很容易就能夠知道我們需要做的兩件事:①構建圖 ②DFS遍歷和BFS遍歷
這裏為了方便起見(同時數據量並不大),這裏將采用鄰接矩陣存儲圖。
代碼:
對結構體結構的定義:
#define max 10 typedef int vertex_type; typedef int edge_type; typedef struct graph_matrix{ int n, e;//頂點數;邊數vertex_type vexs[max];//頂點一維數組 edge_type edges[max][max];//鄰接矩陣二維數組,元素類型為vector<vertex_type> }gm;
全局變量visit[]
//visit[]數組;全局變量 int visit[max] = {0};
①構建圖
//創建圖 void create_gm(gm &gm) { cin>>gm.n>>gm.e; memset(gm.edges, 0, sizeof(gm.edges));for(int i=0; i<gm.n; i++){ gm.vexs[i] = i; } //輸入邊數據 int a, b; for(int i=0; i<gm.e; i++){ cin>>a>>b; gm.edges[a][b] = 1; gm.edges[b][a] = 1; } }
②DFS遍歷
//深度優先 //id: 以id為起始點 void DFS(gm &gm, int id) { visit[id] = 1; cout<<id<<" "; for(int i=0; i<gm.n; i++){ if(gm.edges[i][id] == 1 && visit[i] == 0){ DFS(gm, i); } } }
③BFS遍歷
//寬度優先 void BFS(gm &gm, int id) { visit[id] = 1; queue<int> qu; qu.push(id); while(qu.size() != 0){ int mark = qu.front(); qu.pop(); cout<<mark<<" "; for(int i=0; i<gm.n; i++){ if(gm.edges[i][mark] == 1 && visit[i] == 0){ visit[i] = 1; qu.push(i); } } } }
全部的代碼:
#include<iostream> #include<cstring> #include<queue> using namespace std; #define max 10 typedef int vertex_type; typedef int edge_type; typedef struct graph_matrix{ int n, e;//頂點數;邊數 vertex_type vexs[max];//頂點一維數組 edge_type edges[max][max];//鄰接矩陣二維數組,元素類型為vector<vertex_type> }gm; //函數聲明 void create_gm(gm &gm); void DFS(gm &gm, int id); void BFS(gm &gm, int id); //visit[]數組;全局變量 int visit[max] = {0}; int main() { gm gm;//定義一個叫做gm的鄰接矩陣 create_gm(gm); //調用DFS遍歷 for(int i=0; i<gm.n; i++){ if(visit[i] == 1)continue; cout<<"{ "; DFS(gm ,i); cout<<"}"<<endl; } //重置visit[]數組 memset(visit, 0, sizeof(visit)); //調用BFS遍歷 for(int i=0; i<gm.n; i++){ if(visit[i] == 0){ cout<<"{ "; BFS(gm ,i); cout<<"}"<<endl; } } return 0; } //創建圖 void create_gm(gm &gm) { cin>>gm.n>>gm.e; memset(gm.edges, 0, sizeof(gm.edges)); for(int i=0; i<gm.n; i++){ gm.vexs[i] = i; } //輸入邊數據 int a, b; for(int i=0; i<gm.e; i++){ cin>>a>>b; gm.edges[a][b] = 1; gm.edges[b][a] = 1; } } //深度優先 void DFS(gm &gm, int id) { visit[id] = 1; cout<<id<<" "; for(int i=0; i<gm.n; i++){ if(gm.edges[i][id] == 1 && visit[i] == 0){ DFS(gm, i); } } } //寬度優先 void BFS(gm &gm, int id) { visit[id] = 1; queue<int> qu; qu.push(id); while(qu.size() != 0){ int mark = qu.front(); qu.pop(); cout<<mark<<" "; for(int i=0; i<gm.n; i++){ if(gm.edges[i][mark] == 1 && visit[i] == 0){ visit[i] = 1; qu.push(i); } } } }ALL
總結:
在這個題目中主要是對之前在樹章節中,對關於樹的前序遍歷(DFS)和層次遍歷(BFS)的知識遷移。
① DFS往往會運用到棧來進行實現,而遞歸就是利用棧的一個實現方法,遞歸特性使算法代碼簡潔的同時,也使算法理解困難,
所以對於我這種初學者來說畫圖和動手實踐是最好的學習方法。
例子:“走迷宮,你沒有辦法用分身術同時走進多叉道路中,不撞南墻不回頭。”(來源自網絡)
② BFS則是要運用到隊列,程序流程相對於DFS來說更為清晰。
例子:“當你眼鏡掉了,你趴在地上找,你總是會先摸靠近你的地方,如果沒有,再摸遠一點的地方。”(來源自網絡)
如何對已有知識的新運用也是能力提升的一種,在此我也對DFS和BFS有了更深一層的理解。
嘻嘻:)
列出連通集(DFS及BFS遍歷圖) -- 數據結構