1. 程式人生 > >[C++] C++ DFS 記錄層數兩種寫法dfs(int v) dfs(int v,int level)

[C++] C++ DFS 記錄層數兩種寫法dfs(int v) dfs(int v,int level)

DFS

完整原始碼

DFS.cpp

// DFS.cpp

#include <iostream>
using namespace std;

bool marked[10];
int G[10][10];
int V,E;
int count;

void dfs(int v) {
    count++;

    int level;
    level = count;

    for(int i = 0 ;i < level ;i++)
        cout << " ";

    cout << "DFS   " << v << " start :  "
<< endl; marked[v] = true; for(int i = 0; i < V;i++) if(!marked[i] && G[v][i]) dfs(i); for(int i = 0 ;i < level ;i++) cout << " "; cout << "DFS " << v << " end. " << endl; } void readData() { for(int i = 0; i < 10
;i++) for(int j = 0; j < 10; j++) G[i][j] = -1; cin >> V >> E; for(int i = 0 ; i < E; i++) { int v , w; cin >> v >> w; G[v][w] = 1; } count = 0; } int main() { readData(); dfs(0); }

DFS2.cpp

// DFS2.cpp

#include <iostream>
using namespace std; bool marked[10]; int G[10][10]; int V,E; void dfs(int v, int level) { level++; for(int i = 0 ;i < level ;i++) cout << " "; cout << "DFS " << v << " start : " << endl; marked[v] = true; for(int i = 0; i < V;i++) if(!marked[i] && G[v][i]) dfs(i, level); for(int i = 0 ;i < level ;i++) cout << " "; cout << "DFS " << v << " end. " << endl; } void readData() { for(int i = 0; i < 10;i++) for(int j = 0; j < 10; j++) G[i][j] = -1; cin >> V >> E; for(int i = 0 ; i < E; i++) { int v , w; cin >> v >> w; G[v][w] = 1; } } int main() { readData(); dfs(0, 0); }

模擬資料

DFS

測試執行

4
3
0 1
1 2
2 3

 DFS   0 start :
  DFS   1 start :
   DFS   2 start :
    DFS   3 start :
    DFS   3 end.
   DFS   2 end.
  DFS   1 end.
 DFS   0 end.

--------------------------------
Process exited after 0.9161 seconds with return value 0
請按任意鍵繼續. . .

程式碼說明

有向圖的表示

int G[10][10];
  • 整型二維陣列來表示有向圖,G[v][w] == 1 表示 頂點v 到 頂點w 可達;

DFS過程

  • DFS的本質過程,如果用虛擬碼來描述應該是 :
DFS(int v)
{
    標記 v 為: 已訪問;

    for 對於每個從v可達的頂點w :
        如果 w 還沒被訪問過 ,那就 DFS(w);
}
  • 基於本文使用的二維陣列來表示圖,所以程式碼實現層面可以簡單地用for() 來遍歷整個二維陣列的一行,並且基於G[v][i] 的值來判斷是不是從v可達,具體程式碼如下:
dfs(int v) {
    marked[v] = true;
        for(int i = 0; i < V;i++)
            if(!marked[i] && G[v][i]) dfs(i);
}

DFS.cpp 全域性變數count與本地變數level

int count;

void dfs(int v) {
    count++;

    int level;
    level = count;

    }
  • count在本文中被宣告為一個全域性變數,這樣就不需要在DFS方法中增加引數,直接寫個count++ 就可以在DFS往深處搜尋的時候+1count變數初始值是0、從第一層的1開始最終會變成4
  • level變數是一個區域性變數,是dfs函式內部的變數,目的是記住每個dfs當前的層數,以便在dfs開始start結束end輸出相同數量的空格;

DFS2.cpp 與DFS.cpp記層數

dfs(int v)

void dfs(int v) {
    count++;

    int level;
    level = count;

    marked[v] = true;
    for(int i = 0; i < V;i++)
        if(!marked[i] && G[v][i]) dfs(i);
}

dfs(int v,int level)

void dfs(int v, int level) {
    level++;

    marked[v] = true;
    for(int i = 0; i < V;i++)
        if(!marked[i] && G[v][i]) dfs(i, level);
}
  • 區別還是很明顯的,如果想要記錄下層數,這兩種寫法都是OK的。

聯絡思考

  • 之前實現過 帶權有向圖的環檢測以及環輸出點我,或者見引用[1]),當時用到的就是一種DFS的變形,演算法核心的就是在DFS 開頭以及 結束(對應本文兩次for{} cout 輸出)的位置,顯式地用一個onStak[] 布林陣列來記錄當前被訪問的頂點是不是正處在本次DFS遞迴呼叫;
  • 無論是從模擬資料的圖片還是從測試執行部分的輸出來看,都可以很直觀地感受到DFS,這種遞迴的痕跡,0->1->2->3->3->2->1->0,棧的FILO非常明顯;

引用參考