6.2 图的应用

6.2.1 BFS 广度优先搜索

template<typename Tv, typename Te> void graph<Tv, Te>::BFS(int v, int& clock)   //遍历单个
{
    
    
	queue<int> Q;  //顶点缓存队列
	status(v) = DISCOVERED; //标记顶点为已发现
	Q.enqueue(v);  //将当前顶点入队
	
	while (!Q.empty())   //只要队列非空,则继续
	{
    
    
		v = Q.dequeue();  //每次选择一个顶点出队,遍历其所有邻居,检查是否存在关联边
		dTime(v) = ++clock;
		for (int u = firstNbr(v); u >= 0; u = nextNbr(v, u))   //对于顶点v,从顶点集V的最后一个元素开始寻找邻居(与v存在关联边)
		{
    
    
 
			if (status(u) == UNDISCOVERED)  //如果此邻居顶点尚未发现
			{
    
    			cout << "(v,u)" << "(" << v<<"," << u << ")" << endl;
				status(u) = DISCOVERED;  //设置该顶点为已被发现
				type(v, u) = TREE;   //设置边e(v,u)为TREE(遍历树)
				parent(u) = v;       //设置在遍历树中顶点u的父亲为v
				Q.enqueue(u);        //顶点u入队
			}
			else  //如果此邻居顶点已经被发现
			{
    
    
				type(v, u) = CROSS;   //设置边e(v,u)为CROSS(跨边),不是遍历树枝干
			}
		}
		status(v) = VISITED;   //设置顶点v为已遍历
	}
}
 
template<typename Tv, typename Te> void graph<Tv, Te>::bfs(int s)
{
    
    
	reset();   //复位所有顶点和已存在边的状态为未被发现,未确定
	int clock = 0;  //时间标签
	int v = s;
	do
	{
    
    
		if(status(v)==UNDISCOVERED)
			BFS(v,clock);   //对每个顶点都进行一次单连通域广度优先搜索
		v++;
		cout << "v----" << v << endl;
	} while ((v = (++v%n)) != s);
}

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

6.2.3 DFS应用-拓扑排序

template<typename Tv, typename Te> bool graph<Tv, Te>::TSort(int v, int& clock, stack<Tv>* S)   //(基于DFS)单个连通域的拓扑排序,从连通域的任一顶点开始即可,因为会有外层tSort函数排查尚未发现的顶点
{
    
    
	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;     //标记边e(v,u)为遍历树的枝干
			parent(u) = v;
			if (!TSort(u, clock, S))  //继续深入遍历
				return false;
			break;
		case DISCOVERED:    //若此顶点已被发现但尚未完成遍历,则为回环
			type(v, u) = BACKWARD;
			return false;  //发现此连通域为有环图,不能生成拓扑序列
		default:   //VISITED  发现已经遍历完毕的顶点
			type(v, u) = (dTime(v) < dTime(u)) ? FORWARD : CROSS;  //根据顶点最开始遍历的时间标签dTime判断是前向边还是两个分支的跨边
			break;
		}
	}  
	//此顶点已经完成遍历
	status(v) = VISITED;
	S->push(vdata(v));
	return true;
}
 
template<typename Tv, typename Te> stack<Tv>* graph<Tv, Te>::tSort(int s)
{
    
    
	reset();
	stack<Tv>* S=new stack<Tv>;
	int v = s;
	int clock = 0;
	do
	{
    
    
		if (status(v) == UNDISCOVERED)
		{
    
    
			if (!TSort(v, clock, S))   //如果发现是有环图不能生成拓扑序列,则返回
			{
    
    
				while (!(S->empty()))
				{
    
    
					S->pop(); 
				}
				break;
			}
		}
	} while ((v=(++v)%n)!=s);
	return S;
}

6.2.4 优先级搜索(PFS)

template<typename Tv, typename Te> template<typename PU> void graph<Tv, Te>::PFS(int s, PU prioUpdater)   //(单个连通域)优先级搜索
{
    
    
	priority(s) = 0;      //设置s的优先级最高
	status(s) = VISITED;  //标记顶点s为已经便利的
	cout << "选中的顶点:" << vdata(s) << endl;
	parent(s) = -1;       //这句可以不要,因为reset()已经置-1
	while (true)
	{
    
    
		for (int w = firstNbr(s); w > -1; w = nextNbr(s, w))   //遍历顶点s的所有邻居
		{
    
    
			prioUpdater(this, s, w);  //更新顶点w的优先级和父顶点
		}
		for (int shortest = INT_MAX, w = 0; w < n; w++)
		{
    
    
			if (status(w) == UNDISCOVERED)   //如果顶点w尚未被遍历
				if (priority(w) < shortest)
				{
    
    
					shortest = priority(w);
					s = w;       //更新级数最小的点
				}
		}
		if (status(s) == VISITED) break;   //如果所有顶点均已经访问,则结束
		status(s) = VISITED; 
		cout << "选中的顶点:"<<vdata(s) << endl;
		cout << parent(s) << endl;
		type(parent(s), s) = TREE;
	}
}
 
template<typename Tv, typename Te> template<typename PU> void graph<Tv, Te>::pfs(int s, PU prioUpdater)
{
    
    
	reset();
	int v = s;
	do
	{
    
    
		if (status(v) == UNDISCOVERED)
			PFS(v, prioUpdater);
	} while ((v = (++v%n)) != s);
}

6.2.5 PFS应用-最小支撑树(Prim算法)

template<typename V, typename E> struct PrimPU
{
    
    
	void operator()(graph<V, E>* g, int uk, int v)
	{
    
    
		if (g->status(v) == UNDISCOVERED)   //若顶点v尚未被发现
			if ((g->weight(uk, v)) < (g->priority(v)))  //比较当前边的权重和之前遍历时设置的优先级数
			{
    
    
				g->priority(v) = g->weight(uk, v);   //根据权重设置优先级数
				g->parent(v) = uk;   //更新父节点
				cout << "寻找顶点(uk,v)" << "(" << uk << "," << v << ")" <<"----w---"<<g->weight(uk,v)<< endl;
			}
	}
};
 
template<typename Tv, typename Te> void graph<Tv, Te>::prim(int s)
{
    
    
	PrimPU<Tv, Te> prioUpdater;
	pfs(s, prioUpdater);
}

6.2.6 PFS应用-最短路径(Dijkstra算法)

template<typename V, typename E> struct DijkstraPU
{
    
    
	void operator()(graph<V, E>* g, int uk, int v)
	{
    
    
		if (g->status(v) == UNDISCOVERED)   //如果发现顶点v尚未被发现
		{
    
    
			if ((g->weight(uk, v) + g->priority(uk)) < (g->priority(v)))
			{
    
    
				g->priority(v) = g->weight(uk, v) + g->priority(uk);   //更新优先级数
				g->parent(v) = uk;
			}
		}
	}
};
 
template<typename Tv, typename Te> void graph<Tv,Te>::dijkstra(int s)
{
    
    
	DijkstraPU<Tv, Te> prioUpdater;
	pfs(s, prioUpdater);
}

猜你喜欢

转载自blog.csdn.net/ZXG20000/article/details/113855415