把子项目、工序、课程等看成是图中一个顶点,将顶点称为活动,用图中有向边表示各个活动之间的先后关系,如果从顶点vi到vj之间存在有向边<vi,vj>,则表示活动vi必须优先于活动vj进行。这样的DAG图称为顶点表示活动的网(Activity On Vertex Network),简称AOV。
在AOV网中不能存在回路,因为回路中隐含了相互冲突的条件,可能会出现某个活动将以自己为先决条件的情况,因此回路上的所有活动都不能进行。
对于一个AOV网,常常需要将他的所有活动按照它们之间的先后顺序排成一个线性序列,使得在线性序列中,任何一个活动不依赖于排在它后面的活动。这种有序序列称为拓扑排序(Topological Order),构造拓扑序列的过程称为拓扑排序(Topological Sort)。
- 深度优先排序
void TopSort_DFS(Graph& G){
for(int i = 0; i < G.VerticesNum; i++) //将图中所有顶点的是否被访问的标志位初始化为false
G.isvisted[i] = false;
for(int i = 0; i < G.VerticesNum; i++)
if (G.isvisted[i] == false)
Do_TopSort(G,i); //递归深度搜索
}
void Do_TopSort(Graph &G, int i){
G.isvisted = true;
for(w = G.firstAdj(i); w!=-1; w = NextAdj(i,w)) //firstAdj(i)是获得顶点i第一个相邻的顶点的编号,NextAdj(i,w)是获得顶点i在顶点w之后的下一个相邻顶点
if(G.isvisted[w] == false)
Do_TopSort(G,w);
cout<<i<<"\t";
}
ps:深入优先搜索的拓扑排序只适用于DAG图,对于环路会报错。
- 广度优先排序
使用队列代替递归来实现拓扑排序。具体步骤如下:
(1)计算各个节点的入度,邻接矩阵的行为出度,列为入度;
(2)所有入度为0的节点放进一个队列;
(3)如果队列为空,则转到第(7)步;
(4)如果队列非空,将队头元素从队列中删除,并输出队头元素;
(5)把它的每一个邻接顶点的入度减一,将入度变为0的顶点立刻入队;
(6)到第(3)步,循环执行,直到队列为空;
(7)如果所有顶点均已输出,则给出了一个广度优先的拓扑排序,如果有剩余顶点未被输出,且当前队列为空,则认为存在回路。
ps:因此广度优先的拓扑排序也是检验回路的一种方法。