深度優先搜尋DFS——圖鄰接表表示
阿新 • • 發佈:2019-02-11
作為圖的一個基本演算法,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的那個未訪問結點;
棧:每次找到一個未訪問過的結點,都立刻存入棧。將當前結點的所有未訪問過的結點儲存到棧後,再由棧彈出一個最近放的結點作為新結點做深度遍歷。所以每次輸出連結串列中最接近尾的那個未訪問結點。