深度优先搜索算法
1、DFS概念
DFS是指从图中的某个顶点v出发,优先沿着深度方向遍历该图。其基本过程为:选择一个初始顶点,然后访问该顶点,再从该顶点的某个未曾被访问的邻接点出发进行遍历并访问该点,依次类推,直至所有与该初始顶点想通的顶点被访问到。此时若还有其他未被访问到的点,则选择该未被访问到的结点,继续以上过程。
假设一个无向图如下图所示:
其深度优先搜索过程:
首先访问结点A,然后找到与结点A相邻接的点:B和C,选择B并访问结点B,然后找到与结点B的相邻接的点A、D和E,由于A已经被访问过,因此选择结点D并访问结点D,然后找到与结点D相邻接的点B和结点H,由于结点B被访问过,因此选择结点H并访问结点H,再找到与结点H相邻接的点D和E,由于D被访问过,因此选择结点E并访问结点E,找到与结点E相邻接的点B和H,但该两点都已经被访问了,因此沿着原路返回:H->D-b->A,当搜索返回到结点A时,找到与A相邻的结点B和C,由于C没有被访问,因此继续选择结点C并访问结点C,依次类推,逐渐访问该无向图。下图中的绿线表示深度搜索时逐步访问的点的顺序,虚线表示递归调用时搜索返回的路径。
经过以上的分析可以,遍历图即查找图中结点的邻接顶点的过程。
2.实现
2.1 非递归实现
思路:首先初始化访问标记数组visited[n] = false,然后从图的顶点出发,访问该顶点并弹出该顶点,利用栈将当前顶点的所有邻接结点压入该栈。然后取出栈顶元素并访问栈顶元素,然后再将该栈顶元素的所有邻接点压入栈。不断地重复该过程。
Status DFSTraverse(ALGraph G){ //非递归形式 stack<int> S; for(int i = 0; i<G.vertexNum; i++) visited[i] = false; for(int v = 0; v<G.vertexNum; v++){ if(!visited[v]){ S.push(v); while(!S.empty()){ int u = S.top(); S.pop(); if(!visited[u]){ visited[u] = true; cout<<"node: "<<G.vertices[u].data<<" "; } for(int w = FirstAdjVex(G,u); w>= 0; w = NextAdjVex(G, u, w)){ S.push(w); } } } } return 1; }
2.2 递归实现
思路:首先初始化访问标记数组visited[n]=false。从图中的顶点出发,访问该结点,并标记该结点已经被访问了,然后对该顶点的邻接结点递归的访问并标记已经被访问了。
void DFS(ALGraph G, int j){
visited[j] = true;
cout<<"node: "<<G.vertices[j].data<<" ";
for(int k = FirstAdjVex(G, j); k>=0; k = NextAdjVex(G, j, k)){
if(!visited[k])
DFS(G, k);//针对结点j的所有未曾被访问到的结点,继续递归调用
}
}
Status DFSTraverse1(ALGraph G){
//递归
for(int i = 0;i<G.vertexNum; i++) visited[i] = false;
for(int j = 0;j<G.vertexNum; j++)
if(!visited[j])
DFS(G,j);
return 1;
}
上图中的递归调用过程:
3.全部代码
注意:在该代码中,图的存储方式为邻接表。另外,一个图的深度优先搜索有不同种顺序。
#include "stdafx.h" #include <iostream> #include <string> #include <queue> #include <stack> #define MAX_VERTEX_NUM 20 using namespace std; typedef int infoType;//弧信息 typedef char vertexType;//顶点保存字符信息 typedef int Status; typedef struct ArcNode{ int adjvex; struct ArcNode *nextArc; infoType *info; }ArcNode; typedef struct VertexNode{ vertexType data; ArcNode *firstArc; }VertexNode, AdjList[MAX_VERTEX_NUM]; typedef struct ALGraph{ AdjList vertices; int vertexNum, arcNum; string kind; }ALGraph; int locateNode(ALGraph &G, VertexNode node){ for(int i=0; i<G.vertexNum;i++){ if(node.data == G.vertices[i].data) return i; } return -1; } void insertArcAction(ALGraph &G, int nodeNum1, int nodeNum2); Status insertArc(ALGraph &G, VertexNode node1, VertexNode node2); Status createGraph(ALGraph &G, string kind, int vertexNum, int arcNum){ //采用邻接表构造图(有向或无向图) G.kind = kind; G.vertexNum = vertexNum; G.arcNum = arcNum; //初始化顶点信息 for(int i = 0; i<G.vertexNum; i++){ cin>>G.vertices[i].data; G.vertices[i].firstArc = NULL; } cout<<"Try to input arcs info"<<endl; for(int j = 0; j<G.arcNum; j++){ cout<<"please input two nodes of "<<j+1<<"-th arc"<<endl; VertexNode node1, node2; cin>>node1.data>>node2.data; insertArc(G, node1, node2); } return 1; } void insertArcAction(ALGraph &G, int nodeNum1, int nodeNum2){ ArcNode *p; ArcNode *arc; arc = new ArcNode[1]; arc->adjvex = nodeNum2; p = G.vertices[nodeNum1].firstArc;//相当于链表的插入 if(!p){ G.vertices[nodeNum1].firstArc = arc; arc->nextArc = NULL; } else{ G.vertices[nodeNum1].firstArc = arc; arc->nextArc = p; } } Status insertArc(ALGraph &G, VertexNode node1, VertexNode node2){ int nodeNum1 = locateNode(G, node1);//i和j表示AdjList[MAX_VERTEX_NUM]中的位置 int nodeNum2 = locateNode(G, node2); if(nodeNum1<0 || nodeNum2<0) exit(-1); if(G.kind == "DG") insertArcAction(G, nodeNum1, nodeNum2); else{ insertArcAction(G, nodeNum1, nodeNum2); insertArcAction(G, nodeNum2, nodeNum1); } return 1; } Status printALGraph(ALGraph &G){ for(int i = 0; i<G.vertexNum; i++){ cout<<i<<" "<<G.vertices[i].data; ArcNode *arc = G.vertices[i].firstArc; while(arc){ cout<<"-->"<<arc->adjvex; arc = arc->nextArc; } cout<<"-->NULL"<<endl; } return 1; } bool visited[MAX_VERTEX_NUM]; int FirstAdjVex(ALGraph G, int j){ ArcNode *firstArc = G.vertices[j].firstArc; if(firstArc) return (firstArc->adjvex); else return -1; } int NextAdjVex(ALGraph G, int j, int k){ ArcNode *firstArc = G.vertices[j].firstArc; ArcNode *cur = firstArc; if(!firstArc) return -1; else{ while(cur){ if(cur->adjvex == k) break; cur = cur->nextArc; } } if(cur->nextArc) return (cur->nextArc->adjvex); else return -1; } Status DFSTraverse(ALGraph G){ //非递归形式 stack<int> S; for(int i = 0; i<G.vertexNum; i++) visited[i] = false; for(int v = 0; v<G.vertexNum; v++){ if(!visited[v]){ S.push(v); while(!S.empty()){ int u = S.top(); S.pop(); if(!visited[u]){ visited[u] = true; cout<<"node: "<<G.vertices[u].data<<" "; } for(int w = FirstAdjVex(G,u); w>= 0; w = NextAdjVex(G, u, w)){ S.push(w); } } } } return 1; } void DFS(ALGraph G, int j){ visited[j] = true; cout<<"node: "<<G.vertices[j].data<<" "; for(int k = FirstAdjVex(G, j); k>=0; k = NextAdjVex(G, j, k)){ if(!visited[k]) DFS(G, k); } } Status DFSTraverse1(ALGraph G){ //递归形度式深优先访问树 for(int i = 0;i<G.vertexNum; i++) visited[i] = false; for(int j = 0;j<G.vertexNum; j++) if(!visited[j]) DFS(G,j); return 1; } int _tmain(int argc, _TCHAR* argv[]) { ALGraph G; string kind = "UDG"; int vertexNum = 9; int arcNum = 9; cout<<"Try to create a Adjacency list Graph ..."<<endl; createGraph(G, kind, vertexNum, arcNum); cout<<"Try to print a Adjacence list Graph ..."<<endl; printALGraph(G); cout<<"Try to traverse a undigraph in a regular form..."<<endl;//非递归 DFSTraverse(G); cout<<"Try to traverse a undigraph in a iterational form..."<<endl;//递归 DFSTraverse1(G); system("pause"); return 0; }