深度优先搜索算法
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;
}