通常我们把计划、施工过程、生产流程、程序流程等都当成一个工程,一个大的工程常常被划分成许多较小的子工程,这些子工程称为活动。这些活动完成时,整个工程也就完成了。
例如,计算机专业学生的课程开设可看成是一个工程,每一门课程就是工程中的活动,下图给出了若干门所开设的课程,其中有些课程的开设有先后关系,有些则没有先后关系,有先后关系的课程必须按先后关系开设,如开设数据结构课程之前必须先学完程序设计基础及离散数学,而开设离散数学则必须先并行学完高等数学、程序设计基础课程
AOV网——Activity On Vertex Network
用顶点表示活动,用弧表示活动间的优先关系的有向图,称为顶点表示活动的网。
AOV 网中不能有回路
拓扑排序:
假设G=(V,E)是一个具有n个顶点的有向图,V中顶点序列vl,v2,…,vn称做一个拓扑序列(TopologicalOrder),当且仅当该顶点序列满足下列条件:若在有向图G中存在从顶点vi到vj的一条路径,则在顶点序列中顶点vi必须排在顶点vj之前。通常,在AOV网中,将所有活动排列成一个拓扑序列的过程叫做拓扑排序(TopologicalSort)。
进行拓扑排序的方法:
输入AOV网络。令 n 为顶点个数。
前驱的顶点, 并输出之;
重复以上 ·、¸ 步,直到全部顶点均已输出,拓扑有序序列形成,拓扑排序完成;或图中还有未输出的顶点,但已跳出处理循环。这说明图中还剩下一些顶点,它们都有直接前驱,再也找不到没有前驱的顶点了。这时AOV网络中必定存在有向环。
在实现拓扑排序的算法中,采用邻接表作为有向图的存储结构,每个顶点设置一个单链表,每个单链表有一个表头结点,在表头结点中增加一个存放顶点入度的域count,这些表头结点构成一个数组,表头结点定义如下:
typedefstruct //表头结点
{ Vertex data; //顶点信息
int count; //存放顶点入度
ArcNode *firstarc; //指向第一条弧
}Vnode;
在执行拓扑排序的过程中,当某个顶点的 入度为零(没有前驱顶点)时,就将此顶点 输出,同时将 该顶点的所有后继顶点的入度减1,相当于删除所有以该顶点为尾的弧。为了 避免重复检测顶点的入度是否为零,需要 设立一个栈来存放入度为零的顶点。执行拓扑排序的算法如下:void topsort(VNode adj[],int n)
{ int i,j;
int stack[MAXV],top=0; //栈stack的指针为top
ArcNode *p;
for(i=0;i<n;i++)
if(adj[i].count==0)
{ top++; stack[top]=i;
}
while(top>0) //栈不为空
{ i=stack[top];
top--; //顶点vi出栈
printf(“%d”,i); //输出vi
p=adj[i].firstarc; //指向以vi为弧尾的第一条弧
while(p!=NULL)
{ j=p->adjvex; //以vi为弧尾的弧的另一顶点vj
adj[j].count--; //顶点vj的入度减1
if(adj[j].count==0) //入度为0的相邻顶点入栈
{ top++; stack[top]=j;
}
p=p->nextarc; //指向以vi为弧尾的下一条弧
}
}
}
对于有n个顶点和e条边的有向图而言,for循环中建立入度为0的顶点栈时间为O(n);若在拓扑排序过程中不出现有向环,则每个顶点出栈、入栈和入度减1的操作在while(top>0)循环语句中均执行e次,因此拓扑排序总的时间花费为 O ( n+e )。看下面例题来了解拓扑排序