拓扑排序

懵懂的女人 提交于 2019-11-27 22:02:46

有向无环图

如果一个有向图的任意顶点之间都无法通过一些有向边回到自身,那么称这个有向图为有向无环图(Directed Acyclic Graph,DAG).

拓扑排序

拓扑排序是将有向无环图G的所有顶点排成一个线性序列,使得对图G中的任意两个顶点u,v,如果存在边u->v,那么在序列中u一定在v前面,这个序列又被称为拓扑序列。

求解拓扑序列的方法

步骤如下:

一、定义一个队列Q,并把所有入度为0的结点加入序列。

二、取队首结点,输出。然后删除所有从它出发的边,并令这些边到达的顶点的入度减1,如果某个顶点的入度减为0,则将其加入队列。

三、反复进行步骤二,直到队列为空,如果队列为空时入过队的结点数目恰好为N,说明拓扑排序成功,图G为有向无环图,否则,拓扑排序失败,图G中有环。

可使用邻接表来实现拓扑排序。显然,由于需要记录结点的入度,因此需要额外建立一个数组inDegree[MAXV],并在程序一开始读入图时就记录好每个结点的入度。接下来就只需要按上面的步骤进行实现即可。

拓扑排序的代码如下:

#include<bits/stdc++.h>
using namespace std;
vector<int>G[MAXV];//邻接表
int n,m,inDegree[MAXV];//顶点数,入度
//拓扑排序
bool topologicalSort(){
	int num=0;//记录加入拓扑序列的顶点数
	queue<int>q;
	for(int i=0;i<n;i++){
		if(inDegree[i]==0){
			q.push(i);//将所有入度为0的点加入队列 
		}
	} 
	while(!q.empty()){
		int u=q.front();//取队首队列
		//printf("%d",u)//此处可输出顶点u,作为拓扑序列中的ing点
		q.pop();
		for(int i=0;i<G[u].size();i++){
			int v=G[u][i];
			inDegree[v]--;
			if(inDegree[v]==0){
				q.push(v);//入度为0则进入队列 
			}
		} 
		G[u].clear();//清空顶点U的所有出边,如无必要,可以不写
		num++; //加入拓扑序列中的顶点加1 
	}
	if(num==n) return true;//加入拓扑序列中的顶点数为n,说明拓扑排序成功
	else return false;//失败 
} 

拓扑排序很重要的一个应用就是判断一个给定的图是否是有向无环图。正如上面的代码,如果topologicalSort()函数返回true,则说明拓扑排序成功,给定的图是有向无环图,否则,说明拓扑排序失败,给定的图有环

最后指出,如果要求有多个入度为0的顶点,选择编号最小的顶点,那么把queue改成priority_queue,并保持队首元素(堆顶元素)是优先队列中的最小的元素即可(当然用set也是可以的)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!