算法思想
按照有向图给出的次序关系,将图中顶点排成一个线性序列,对于有向图中没有限定次序关系的顶点,则可以人为加上任意的次序关系,由此所得顶点的线性序列称之为拓扑有序序列。显然对于有回路的有向图得不到拓扑有序序列,因为有回路的话,顶点的先后次序就不确定了。
例如,下图,我们可以人为限定次序:A B C D 或 A C B D

如何进行拓扑排序?
- 从有向图中选取一个没有前驱(没有在它之前活动)的顶点,输出之;
- 从有向图中删去此顶点以及所有以它为尾的弧;
- 重复上述两步,直至图空,或者图不空但找不到无前驱的顶点为止。
没有被打印输出的顶点构成回路了。
例如,A C B H G D F E(不唯一)。可以发现图中所有顶点都被打印输出了,证实了这个有向图中不存在回路。

拓扑排序的第一步,首先找到没有前驱的顶点,那么没有前驱的顶点,它的特征是什么呢?我们在算法里,如何去找没有前驱的顶点呢?
没有前驱的顶点==入度为零的顶点
删掉这个顶点以及它所对应的出度的弧,又该如何实现呢?
删除顶点及它的出弧==弧头顶点的入度-1
拓扑排序实现

获取各顶点入度的函数:
void FindID(AdjList G, int indegreeIMAX_VERTEX_NUM]){
int i;
ArcNode *p;
for(i=0;i<G.vexnum;i++)
indegree[i]=0;
for(i=0;i<G.vexnum;i++){
p=G.vertexes[i].firstarc;//找邻接点
while(p!=NULL){
indegree[p->adjvex]++;
p=p->nextarc;
}
}
}
可以将入度为0的点单独存储,将入度为0的点入队。
int TopoSort(AdjList G){
Queue Q;/*队列存储入度为0*/
int indegree[MAX_VERTEX_NUM];//存放每个顶点的入度值
int i,count,k;//count计数,然后和有向图中顶点总数比较
ArcNode*p;
FindID(G,indegree);
InitStack(&S);//初始化队列
for(i=0;i<G.vexnum;i++)
if(indegree[i]==0) EnterQueue(&Q,i);//入队
count=0;
while(!StackEmpty(S)){
DeleteQueue(&Q,&i);//一个入度为0的点出队
printf("%c",G.vertex[i].data);
count++;
p=G.vertexes[i].firstarc;
while(p!=NULL){
k=p->adjvex;
indegree[k]--;
if(indegree[k]==0) EnterQueue(&S,k);
p=p->nextarc;
}
}
if(count<G.vexnum) return(Error);//有向图中有回路
else return(Ok);
}
时间复杂度
如果AOV网络有n个顶点,e条边,在拓扑排序的过程中,搜索入度为零的顶点所需的时间是O(n)。在正常情况下,每个顶点进一次栈,出一次栈,所需时间O(n)。每个顶点入度减1的运算共执行了e次。所以总的时间复杂为O(n+e)。
拓扑排序是对有向无环图(DAG)的顶点进行排序,使得对于每一条有向边uv,都有u在排序序列之前。本文介绍了拓扑排序的概念、如何进行拓扑排序,以及拓扑排序的实现过程和时间复杂度。
277

被折叠的 条评论
为什么被折叠?



