三、【图算法】深度优先搜索(DFS)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_18108083/article/details/84873092

图算法是个庞大的家族,其中大部分成员的主体框架都可以归结于图的遍历。图的遍历需要访问所有顶点一次且仅 一次,此外,图遍历同时还要访问所有的边一次且仅一次。经过一次遍历,树边的顶点共同构成了原图的一颗遍历树

为防止对顶点的重复访问,在遍历的过程中,需要动态地设置各顶点的不同状态,并且随着遍历的进程不断地转换状态,直至最后的“访问完毕”,图的遍历更加强调对处于特定状态顶顶啊的甄别和查找,故也称作图搜索

最基本而典型的图搜索算法包括:广度优先搜索(BFS),深度优先搜索(DFS),优先级搜索等(PFS),本文主要介绍图的深度优先搜索(depth-first search,DFS),本文使用的图数据结构参见之前博客https://blog.csdn.net/qq_18108083/article/details/84870399

策略:优先选取最后一个被访问到的顶点的邻居。始自图中顶点s的BFS搜索,将首先访问顶点s,再从s所有尚未访问到的邻居中任取一个顶点,并以此为基点,递归地执行DFS搜索。这个过程具有先入先后的特点,故采用栈结构作为辅助容器或直接使用递归方法,这里使用递归进行实现。

实现:由于整个图可能具有多个连通域,从单个顶点开始的DFS可能不能遍历到图中的所有顶点,所以DFS函数能够遍历从顶点s开始的单个连通域,而dfs函数则对所有顶点进行检查,只要未曾被访问过,就从该点开始一次新的DFS搜索,这样就能保证所有的连通域都能够被遍历到。

template<typename Tv, typename Te> void graph<Tv, Te>::DFS(int v, int& clock)
{
	status(v) = DISCOVERED;    //标记当前节点为发现
	dTime(v) = ++clock;

	for (int u = firstNbr(v); u > -1; u = nextNbr(v, u))  //遍历所有邻居顶点
	{
		switch (status(u))
		{
		case UNDISCOVERED:   //尚未发现的顶点,继续深入遍历
			status(u) = DISCOVERED;  //标记为已发现
			type(v, u) = TREE;
			parent(u) = v;
			DFS(u, clock);
			break;
		case DISCOVERED:     //已被发现但是尚未遍历完成的顶点,那就是祖先啊
			type(v, u) = BACKWARD;
			break;
		default:   //VISITED  已经遍历完成,根据dTime判断是FORWARD还是CROSS
			type(v, u) = (dTime(v) < dTime(u)) ? FORWARD : CROSS;
			break;
		}
	}
	status(v) = VISITED;
	fTime(v) = ++clock;
}

template<typename Tv, typename Te> void graph<Tv, Te>::dfs(int s)
{
	reset();   //复位所有顶点和已存在边的状态为未被发现,未确定
	int clock = 0;  //时间标签
	int v = s;
	do
	{
		if (status(v) == UNDISCOVERED)
			DFS(v, clock);   //对每个顶点都进行一次单连通域深度优先搜索
		cout << "v----" << v << endl;
	} while ((v=(++v%n)) != s);
}

效率:若图G=(V,E)中共有n个顶点和e条边,则DFS仅需O(n+e)时间。

猜你喜欢

转载自blog.csdn.net/qq_18108083/article/details/84873092