深度优先搜索算法

深度优先搜索算法

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;
}


猜你喜欢

转载自blog.csdn.net/bible_reader/article/details/71436325