如果有向图中用顶点表示活动而用弧表示活动间的优先关系,则该有向图为顶点表示活动的网成为AOV网(Activity On Vertex network)。
显然,AOV网应是有向无环图即DAG图。这是因为工程中的各子工程(活动)先后有序不可能存在环,若存在意味着一个子工程以自身的后续子工程的完成为开始条件的谬论。所有,对设计的工程流程图即给定的AOV网,首先要检查它是否存在环路。
检查的办法是构造它的顶点的拓扑有序序列。若AOE网中的所有顶点都在它的拓扑有序序列中,则该AOV网中必定不存在环。所构造出的拓扑有序序列的特点是:
(1).在AOV网中,若顶点i领先于顶点j,则在拓扑有序序列中依然领先。
(2).对于网中无领先关系的顶点i,j,在拓扑有序序列建立一个领先关系,或者i领先于j,或者j领先于i。
拓扑排序就是由AOV网中顶点集合上偏序关系得到该集合的一个全序关系的操作。对于任何一个工程中的各个子工程的安排,必须按照其中某一个拓扑有序序列中的顺序进行安排。那么如何进行对AOV网进行拓扑排序?其方法和步骤如下:
(1).从AOV网中选择一个入度为0的顶点输出它;
(2).从网中删除该顶点和以它为尾(即从它出发)的所有弧;
(3).重复(1)和(2),直到网中不存在入度为0的顶点时止。
操作的结果有两种可能,一种是网中全部结点均已经输出,拓扑排序完成;一种是有剩余顶点未被输出,但无入度为0的顶点,说明网中有环路。
现在我们讨论拓扑排序算法的实现问题。对AOV网采用邻接表存储结构,并且在表头结点中增加一个域indegree来存放顶点的入度。选择并输出一个入度为0可通过查表头数组实现,而删除顶点和以它为弧的操作用弧头的入度减1来实现。
为了避免重复检测入度为0的顶点,把所有入度为0的顶点来保存于一链栈中,每当输出从栈中弹出一个,每当出现新的入度为0的顶点便压入之。其算法步骤如下:
(1).将所有入度为0的顶点入栈;
(2).弹出栈顶元素输出,并把各邻接顶点的入度域值减1;
(3).将新产生的入度为0的顶点入栈;
(4).重复(2)、(3)两步,直到栈空时为止。
在这里栈仅起保存入度为0的顶点的作用,入度为0的顶点谁先谁后无关紧要,故也可以用链队列或数组来保存。可借用值为0的入度域indegree存放链中的指针,把入度域为0的表头结点链接起来形成链栈。
typedef struct node//表结点
{
int adjvex;//邻接点域
struct node *next;//指向下一个表结点的指针
}nodetype;//表头结类型
typedef struct frontnode//表头结点
{
vertextype data;//顶点域
int indegree; //入度域
struct node *next;//指向第一个表结点的指针
}frontnodetype;//邻接表结点类型
typedef frontnodetype adjlist[maxvernum];//邻接表类型
拓扑排序算法可用C语言描述如下。函数toposort值为0时说明AOV网中存在环路,无法给出所有顶点的拓扑有序序列;否则为1时拓扑排序成功,输出AOV网中全部顶点的拓扑有序序列。
int toposort(adjlist g[],int n)//AOV网以带入度的邻接表g存储,算法求其一种拓扑有序序列
{
int i,j,k,m=0;//定义局部量,并初始化统计变量m
int top=0;//栈顶指针初始化
nodetype *p;//定义指针初始化
for(i=1;i<=n;i++)//把所有入度为0的顶点压入栈顶
if(g[i].indegree==0)//如果入度为0
{
g[i].indegree=top;//栈顶指针值存入入度域
top=i;//栈顶指针指向新栈顶
}
while(top!=0)//开始拓扑排序
{
j=top;//栈顶指针送j
top=g[top].indegree;//从栈顶弹出一个元素
printf("%d\n",g[j].data);//假定顶点值为顶点序号,整型,输出原栈顶的值
m++;//统计输出的顶点个数
p=g[j].next;//p指向第j个链表的第一个节点
while(p!=NULL)//当第j个链表不空
{
k=p->adjvex;//p所指结点邻接点域值送k中
g[k].indegree--;//第k个表头结点的入度域减1
if(g[k].indegree==0)//如果入度域为0则压入链栈中
{
g[k].indegree=top;//栈顶指针值存入其入度域
top=k;//更新栈顶指针值为k
}
p=p->next;//p指向下一个邻接点
}
}
if(m<n)//若m<n,打印AOV网中有环路并返回0
{
printf("The AOV network has a cycle\n");
return 0;
}
else
return 1;//否则返回1
}