定义:
拓扑排序是上AOV网上的应用,AOV网即是顶点活动网(active on vertex network),顶点表示活动,边表示活动间的某种约束关系。如果图中所有顶点可以排成一个线性序列,且如果从顶点Vi到Vj存在一条路径,则在序列中顶点Vi一定排在Vj之前,就把这种序列称为拓扑序列,构造拓扑序列的操作叫作拓扑排序。如下图中,用顶点表示课程,有向边表示课程之间的优先关系,
图中一个拓扑序列为C0,C1,C2,C4,C3,C5,C8,C6。如果一个学生同时只能选修一门课,则他必须按照某一个拓扑序列的次序学习,从而保证学习任何一门课时,之前应该修的课程已经完成。
注意,一个AOV网的拓扑序列不一定存在,也不一定唯一,而且一定不能出现回路,因为出现回路意味着某些活动的开工是以自己工作的完成作为先决条件,这种现象叫做死锁,不可行。
拓扑排序的思想:
1)从AOV网中选择一个入度为0的顶点将其输出。
2)在AOV网中删除此顶点及其所有的出边。
重复1)2),直到所有顶点都已经输出为止,此时整个拓扑排序完成;或者直到剩下的顶点的入度都不为0,此时说明AOV网存在回路,不存在拓扑序列。
储存结构:
1.AOV网用邻接表表示,边表为出边表。
2.定义一个indegree [VN] 存放各顶点的入度,利用入度为0的数组元素空间构造一个链接表示的栈,所有进入栈的顶点入度都为0。
3.排序的结果放在整形数组中,每个整数元素为结点表中下标对应的顶点。
上面的AOV网的邻接表表示如图,
算法:
在排序之前,调用findInDegree确定所有顶点的入度,再将所有入度为0的顶点入栈。接下来执行topo函数:
1)从栈顶取出一个顶点将其输出,由它的出边表得到以该顶点为起点的出边,将这些边的终点的入度减少1,即删除这些出边。
2)如果某条边的终点的入度为0,则将该顶点入栈。
重复1)2),直到栈为空。
如果topo函数返回的顶点数(入度为0)小于VN,说明AOV网存在回路,否则拓扑序列正常结束。
C++代码实现:
#include <iostream>
#define Adjtype int
#define Vextype int
#define VN 2018
using namespace std;
typedef struct Edgenode *PEdgenode;
typedef struct Edgenode *Edgelist;
struct Edgenode{
int endvex;//相邻顶点在顶点表中的下标
PEdgenode nextedge;//边表中的结点
};
typedef struct{
Vextype vertex;//顶点信息
Edgelist edgelist;//边表头指针
}VexNode;//顶点表中的结点
typedef struct{
VexNode vexs[VN];//顶点表
}GraphList;//图的邻接表表示
void findInDegree(GraphList *PAOV,int *indegree)
{
Edgelist p;
for(int i=0;i<VN;i++) indegree[i]=0;
for(int i=0;i<VN;i++){
p=PAOV->vexs[i].edgelist;
while(p){
indegree[p->endvex]++;//增加入度数
p=p->nextedge;
}
}
}
int topo(GraphList *PAOV,int *ptopo,int *indegree,int top)
{
Edgelist p;
int i,k,cnt=0;
while(top!=-1){
i=top;
ptopo[cnt++]=i;//记入拓扑序列
top=indegree[top];//top顶点退栈
for(p=PAOV->vexs[i].edgelist;p!=NULL;p=p->nextedge){
k=p->endvex;
indegree[k]--;//减少入度数,即删除边
if(indegree[k]==0){
indegree[k]=top;top=k;//入度为0的顶点入栈
}
}
}
return cnt;
}
void topoSort(GraphList *PAOV,int *ptopo)
{
int indegree[VN];
findInDegree(PAOV,indegree);
int top=-1;
for(int i=0;i<VN;i++)
if(indegree[i]==0){
indegree[i]=top; top=i;
}
int cnt=topo(PAOV,ptopo,indegree,top);
if(cnt<VN) cout<<"The AOV has no topo-sort sequence."<<endl;
}