1. 程式人生 > >列出連通集(DFS及BFS遍歷圖) -- 數據結構

列出連通集(DFS及BFS遍歷圖) -- 數據結構

前序 理解 ali 同時 lang 實現 int all 鄰接矩陣

題目:

7-1 列出連通集 (30 分)

給定一個有N個頂點和E條邊的無向圖,請用DFS和BFS分別列出其所有的連通集。假設頂點從0到N1編號。進行搜索時,假設我們總是從編號最小的頂點出發,按編號遞增的順序訪問鄰接點。

輸入格式:

輸入第1行給出2個整數N(0<N10)和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遍歷圖) -- 數據結構