图的拓扑排序详解

定义:

        拓扑排序:图中的点以线性方式进行排序。即若图中有一条边是u->v,则最后的排序结果中u总在v前面。类似于先序图的概念,必须先到达u点才能到达v点,则u>v。

适用条件:

        并不是所有图都可以进行拓扑排序。这里有个重要的概念是离散数学中的偏序关系。

        偏序的大意就是,如果图中的两个点有确定的大小关系,例如一条边上的两个点,或没有直接的联系,即两个点不相通,则就是偏序关系。不能存在互相矛盾的关系,比如环路,例如a->b,b->a,这种就不满足偏序关系。所以,只要一个图中不存在环路,不管图中的点连通与否,都满足偏序关系。而拓扑排序的条件就是这个图是有向无环图(DAG),有向是为了确定两个点的先后顺序,若无向,则关系都乱了。

唯一性:

        图中顶点的拓扑关系并不像数字的大小关系那样简单,这里还有个重要的概念的离散数学中的全序关系。

        全序关系在图中的大意就是,每个点都与其他所有点有着确定的先后顺序,那么这个图就满足全序关系。

        这里用数组与图做对比来解释,任意两个不相等的数字之间有着确定的大小关系,所以数组就满足全序关系,这样排序后的结果就是惟一的。但是通常我们评价排序算法时,要考虑一个因素是稳定性,即相同数字的排序结果是否和出现的顺序一致。因为两个相同的数字的大小关系无法确定,不满足全序关系,那么他们在排序结果中的位置也就无法确定。

        回到图中,如果DAG中的每个点都与其他所有点有确定的先后顺序,那么这个DAG的拓扑排序结果是惟一的,但是如果存在两个点不直接相连,即无法确定他们的拓扑关系,那么它们在拓扑结果中的位置就无法确定,拓扑结果就不唯一了。

基本思想:

        拓扑排序有两种做法,一种是bfs的思路,一种是dfs的思路。本文介绍bfs方法,bfs是以入度为切入点,一个点的入度越小,则排在它前面的点就越少。基本思想是动态维护一个入度为0的顶点的队列。然后取一个点出发,依次将图中与该点相连
的边去掉,如果在过程中又出现了新的入度为0的顶点,则加入队列中,直到队列为空。如果此时图中没有边了,则
不存在环路,从而得到排序结果,这也说明bfs方法可以检测一个图是不是有向无环图。

数据结构:

        算法中涉及到的数据结构有以下几种:

        1、图的邻接矩阵,用来表示图。

        2、保存排序结果的集合,一般用vector。

        3、入度数组,用来保存每个点的入度。

        4、队列,用来保存当前入度为0并且没有遍历到的点。

算法过程:

        1、建图

        2、遍历图中的所有点,统计每个点的入度,存到入度数组中

        3、将入度为0的点入队

        4、对当前队列中的点进行遍历,取出点并将它存到结果集中。再从该点出发,去掉图中以该点为起点的边,并且将边的终点的入度-1。同时判断终点的入度是否减为0,若为0,则入队。

        5、重复4,直到队列为空。

c++代码:

#include
#include
#include
#include
using namespace std;
vector *edge;//边集 
vector res;//结果集 
queue q;
int in[101];//入度数组 
int n,m,edges;//edges表示此时图中所剩的边数 
int main()
{
	int a,b;
	cin>>n>>m;
	edges=m;
	edge=new vector[n];
	memset(in,0,sizeof(in));
	for(int i=0;i>a>>b;
		edge[a].push_back(b);
	}
	//统计入度 
	for(int i=0;i

运行结果:

图的拓扑排序详解_第1张图片

例子中的图有13个点,若是全序关系,则应该有(13-1)*13/2=78条边,显然这个图不满足全序关系,则排序结果不唯一。

你可能感兴趣的:(拓扑排序)