拓扑排序及逆拓扑排序

拓扑排序其实就是对有向无环图的顶点的一种排序,每个顶点出现且只出现一次。

对一个AOV网进行拓扑排序的方法:

1、从AOV网中选择一个入度为0的顶点并输出;

2、从网中删除该顶点和所有以它为起点的有向边;

3、重复1和2直到当前的AOV网为空或当前网中不存在入度为0的顶点为止;

1、拓扑排序算法 

该算法中假设使用邻接表作为存储结构:

//拓扑排序
#define Maxsize 100
int indegree[Maxsize];         //存储当前顶点的入度
int print[Maxsize];           //记录拓扑序列
Stack<int> S;                //存储入度为0的顶点

bool TopologicalSort(Graph G)
{
	InitStack(S);           //初始化栈
	for(int i=0;i<G.vexnum;i++)
	{
		if(indegree[i]==0)     //度为0的顶点入栈 
		{
			push(S,i);
		}
	} 
	int count=0;       //计数
	while(!IsEmpty(S))
	{
		pop(S,i);
		print[count++]=i;
		for(p=G.vertices[i].firstarc;p;p=p->nextarc)//将所有i指向的顶点的入度减1,并且将入度减为0的顶点压入栈中 
		{
			v=p->adjvex;
			if(!(--indegree[v]))
			{
				push(S,v)
			}
		}
		if(count<G.vexnum)     //拓扑排序失败,说明有回路 
		{
			return false;
		}
		else
		{
			return true;
		}
			
	} 
 } 

时间复杂度为:O(|V|+|E|);若采用邻接矩阵存储时,其时间复杂度为O(|V|^2);

2、使用DFS进行拓扑排序 

祖先结点的DFS函数结束时间大于子孙结点的DFS函数结束时间,利用DFS求出各顶点结束时间,对于拓扑排序,就是将结束时间从大到小排序。

 //深度优先遍历实现的拓扑排序
 bool visit[Maxnum];      //标记数组,防止顶点被多次访问 
 void DFSTraverse(Graph G)
 {
 	for(int i=0;i<G.vexnum;i++)
 	{
 		visit[i]=false;
	}
	int time=0;       //记录每个顶点调用DFS函数结束时间 
	for(int i=0;i<G.vexnum;i++)
	{
		if(!visit[i])
		DFS(G,i);
	}
  } 
  void DFS(Graph G,int v)
  {
  	visit[v];
  	visit[v]=true;
  	for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,V,W))  //从顶点v出发,深度优先遍历G
	{
	 	if(!visit[w]);
	 	DFS(G,w);
	} 
	time+=1;
	finishTime[v]=time; 
  } 

3、逆拓扑排序 

逆拓扑排序的步骤:

1、从AOV网中选择一个出度为0的顶点并输出;

2、从网中删除该顶点和所有以它为终点的有向边;

3、重复1和2,直到当前的AOV网为空;

#define Maxsize 100
//拓扑排序
int Dedegree[Maxsize];         //存储当前顶点的出度
int print[Maxsize];           //记录拓扑序列
Stack<int> S;                //存储出度为0的顶点

bool TopologicalSort(Graph G)
{
	InitStack(S);           //初始化栈
	for(int i=0;i<G.vexnum;i++)
	{
		if(Dedegree[i]==0)     //度为0的顶点入栈 
		{
			push(S,i);
		}
	} 
	int count=0;       //计数
	while(!IsEmpty(S))
	{
		pop(S,i);
		print[count++]=i;
		for(p=G.vertices[i].firstarc;p;p=p->nextarc)//将指向i的顶点的出度减1,并且将出度减为0的顶点压入栈中 
		{
			v=p->adjvex;
			if(!(--Dedegree[v]))
			{
				push(S,v)
			}
		}
		if(count<G.vexnum)     //拓扑排序失败,说明有回路 
		{
			return false;
		}
		else
		{
			return true;
		}		
	} 
 } 

4、DFS遍历实现逆拓扑排序 

 //DFS实现的逆拓扑排序
 bool visit[Maxnum];      //标记数组,防止顶点被多次访问 
 void DFSTraverse(Graph G)
 {
 	for(int i=0;i<G.vexnum;i++)
 	{
 		visit[i]=false;
	}
	for(int i=0;i<G.vexnum;i++)
	{
		if(!visit[i])
		DFS(G,i);
	}
  } 
  void DFS(Graph G,int v)
  {
  	visit[v];
  	visit[v]=true;
  	for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,V,W))  //从顶点v出发,深度优先遍历G
	{
	 	if(!visit[w]);
	 	DFS(G,w);
	} 
	cout<<v;           //输出顶点 
  } 

总结:

1、拓扑排序和逆拓扑排序序列都可能不唯一;

2、若图中有环,则不存在拓扑排序序列或者逆拓扑排序序列; 

猜你喜欢

转载自blog.csdn.net/m0_51769031/article/details/125381796