1. 程式人生 > >無向圖及其深度優先搜尋和廣度優先搜尋

無向圖及其深度優先搜尋和廣度優先搜尋

無向圖

圖(Graph)是表示事物與事物之間的關係的數學物件,是數學領域的重要分支——圖論(Graph Theory)的研究物件。圖論中的圖是由若干給定的點及連線兩點的線所構成的圖形,這種圖形通常用來描述某些事物之間的某種特定關係,用點代表事物,用連線兩點的線表示相應兩個事物間具有這種關係。無向圖中邊(edge)僅僅是兩個頂點(vertex)之間的連線,是比較簡單的圖。

我們定義無向圖的結構如下(這裡我選擇用鄰接表來表示無向圖):

#include <map>
#include <forward_list>

using namespace std;

struct UndirectedGraph {
    size_t V, E; //V表示頂點數,E表示邊數
    set<int, forward_list<int>> Graph;
};

深度優先搜尋

 深度優先搜尋(Depth First Search,DFS)是圖論的重要演算法,它的思想是從某一個頂點出發向其鄰近頂點移動(不能重複訪問頂點),直至找到目標或已經無法繼續深入。深度優先遍歷的結束標誌則是從起點出發能到達的所有頂點都已經被訪問過,即結合回溯法來遍歷。對於遍歷,如果圖是連通的,每個鄰接表中的元素都會被訪問到。深度優先遍歷中得到的每一條路徑都是圖的一個連通分量,因此深度優先搜尋常用來解決連通分量的計算問題。

下面是深度優先遍歷的原始碼示例:

void dfs(UndirectedGraph &graph, vector<int> &visited, int v) {
    visited[v] = 1;
    cout << v << " ";
    for (int i : graph.Graph[v])
        if (!visited[i])
            dfs(graph, visited, i);
}

非遞迴版本用後進先出(LIFO)的棧來儲存已經訪問過的頂點,當深入到無路可走時便彈出棧元素,在新的棧頂上繼續進行遍歷。

void dfs(Undirected &graph, vector<int> &visited, int v) {
    if (visited[v] == 1)
        return ;
    cout << v << " ";
    stack<int> st;
    st.push(v);
    while (!st.empty()) {
        int i = st.top();
        forward_list<int>::const_iterator ite;
        for (ite = graph.Graph[i].cbegin(); ite != graph.Graph[i].cend(); ++ite)
            if (!visited[*ite]) {
                cout << *ite << " ";
                st.push(*ite);
                break;
            }
        if (ite == graph.Graph[i].cend())
            st.pop();
    }
}

 廣度優先搜尋

廣度優先搜尋(Breadth First Search,BFS)是在遍歷完當前頂點的所有相鄰頂點後才會轉到下一層頂點去遍歷。廣度優先搜尋常用於尋找最短路徑。

void bfs(UndirectedGraph &graph, vector<int> &visited, int v) {
    queue<int> q;
    visited[v] = 1;
    cout << v << " ";
    q.push(v);
    while (!q.empty()) {
        int tmp = q.front();
        q.pop();
        for (int i : graph.Graph[tmp])
            if (!visited[i]) {
                cout << i << " ";
                q.push(i);
            }
    }
}