拓扑排序

151 阅读1分钟

拓扑排序的定义

在图中求一个有先后关系的顺序,这就是拓扑排序。
排序规则:图中节点没有边指向它排序在前,然后删除由它出发指向别的结点的边,继续寻找没有边指向的结点。

注意:能拓扑排序的充要条件是他是一个有向无环图,有环的图不能进行拓扑排序。

图的入度和出度

出度:以点u为起点的边的数量称为u的出度
入度:以点u为终点的边的数量称为u的入读
由此我们可以想到:一个点的入度为0表示他排在最前面,一个点的出度为0表示他排在最后面。

拓扑排序算法讲解

  1. 首先找到入度为0的点,放入队列中。
  2. 然后再队首去取出结点,边的另一个结点入度-1.如果入度为0则进入队列。

拓扑排序无解判断:最后当队列为空时,还有入度不为0的结点表示图中存在环,没有拓扑排序

//拓扑排序
int e[N],ne[N],h[N];//e终点、ne当前位置指向的下一个位置 、w权值 
int cnt[N];//结点的入度
int idx; 
int n,m;
void init()//初始化 
{
	for(int i=1;i<=n;i++)
	{
		h[i]=-1;//表示没有节点从i出发 
	}
}
void addEdge(int from,int to)//添加节点和边 
{
	cnt[to]++;//入度+1 
	e[idx]=to;
	ne[idx]=h[from];//将当前边插入到 节点from指向的集合中 。 
	h[from]=idx++;//修改from指向的位置。 
}
vector<int> toupsort()
{
	queue<int> q;
	for(int i=1;i<=n;i++) 
	{
		if(cnt[i]==0) q.push(i);//找到入度为0的点,放入队列中。 
	}
	vector<int> ans;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		ans.push_back(u);//将先出队列的结点存入集合中 
		for(int i=h[u];i!=-1;i=ne[i])
		{
			int to=e[i];
			if(--cnt[to]==0)//边的另一个结点入度-1.如果入度为0则进入队列。 
			{
				q.push(to);
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(cnt[i]>0) return vector<int>();//如果还有入度不为0的,表示存在环,没有拓扑排序 
	}
	return ans;
}