拓扑排序其实就是对有向无环图的顶点的一种排序,每个顶点出现且只出现一次。
对一个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、拓扑排序和逆拓扑排序序列都可能不唯一;文章来源:https://www.toymoban.com/news/detail-427524.html
2、若图中有环,则不存在拓扑排序序列或者逆拓扑排序序列; 文章来源地址https://www.toymoban.com/news/detail-427524.html
到了这里,关于拓扑排序及逆拓扑排序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!