作为图的一个基本算法,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的那个未访问结点;
栈:每次找到一个未访问过的结点,都立刻存入栈。将当前结点的所有未访问过的结点保存到栈后,再由栈弹出一个最近放的结点作为新结点做深度遍历。所以每次输出链表中最接近尾的那个未访问结点。