1. 程式人生 > >深度優先搜尋DFS——圖鄰接表表示

深度優先搜尋DFS——圖鄰接表表示

作為圖的一個基本演算法,DFS應用很廣,可以推廣出很多實用的演算法。下面貼出一個比較常用的用鄰接表表示的圖DFS。

/*
圖鄰接表表示DFS
input:
1
7
A 1 5
B 2 4 3
C 2 4 2
D 3 6 5 2
E 3 7 4 1
F 1 4
G 1 5
output:
A E D B C F G(運用遞迴實現)
A E G D F B C(運用棧實現)
*/
#include<iostream>
#include<cstring>
#include<stack>
using namespace std;
struct LinkNode{
    //相鄰結點
    int vex;
    LinkNode *next;
};
struct Graph{
    //圖鄰接表表示
    char data;
    LinkNode *head;
};
void Create(Graph G[],int n){
    //建立圖的鄰接表
    int i,j,m;
    LinkNode *p;
    for(i=1; i<=n; i++){
        cin>>G[i].data;
        G[i].head = NULL;
        cin>>m;
        for(j=1; j<=m;j++){
            p = new LinkNode;
            cin>>p->vex;
            p->next = G[i].head;
            G[i].head = p;
        }
    }
}
/*
void DFS(Graph G[],int v,bool visited[]){
    //圖鄰接表表示DFS
    LinkNode *p;
    visited[v] = true;
    cout<<G[v].data<<' ';
    p = G[v].head;
    while(p != NULL){
        if(!visited[p->vex])DFS(G,p->vex,visited);
        p = p->next;
    }
}
*/
void DFS(Graph G[],int v,bool visited[]){
    //用棧實現DFS圖鄰接表表示
    stack<int> s;
    LinkNode *p;
    int now;
    s.push(v);
    while(!s.empty()){
        now = s.top();
        s.pop();
        visited[now] = true;
        cout<<G[now].data<<" ";
        p = G[now].head;
        while(p != NULL){
            if(!visited[p->vex])s.push(p->vex);
            p = p->next;
        }
    }
}
int main(){
    Graph *G = NULL;
    bool *visited = NULL;
    int t,n;
    cin>>t;
    while(t--){
        cin>>n;
        G = new Graph[n+1];
        visited = new bool[n+1];
        memset(visited,0,sizeof(visited));
        Create(G,n);
        DFS(G,1,visited);
cout<<endl;
    }
    return 0;
}

      注意到,用遞迴方法實現和用棧方法實現輸出的結果是不同的。為什麼呢?因為圖的鄰接點不像二叉樹那樣有規律,所以用不同方法構造DFS得到的遍歷結果具有“任意性”。但是一個方法必然只有一個遍歷結果,而且不同方法的結果都是正確的。兩個方法具體如下:

      遞迴:每次找到一個未訪問過的結點,立刻作為新結點做深度遍歷,所以每次都是輸出連結串列中最接近head的那個未訪問結點;

      棧:每次找到一個未訪問過的結點,都立刻存入棧。將當前結點的所有未訪問過的結點儲存到棧後,再由棧彈出一個最近放的結點作為新結點做深度遍歷。所以每次輸出連結串列中最接近尾的那個未訪問結點。