拓扑排序
应用对象:有向无环图(DAG)
AOV网:用一个有向图表示一个工程的各个子工程及其相互制约的关系,以顶点表示活动,弧表示活动之间的优先制约关系,称这种有向图为顶点表示活动的网,简称AOV网。
应用:拓扑排序
AOE网:用一个有向图表示一个工程的各个子工程及其相互制约的关系,以弧表示活动,以顶点表示活动开始或结束事件,称这种有向图为边表示活动的网,简称AOE网。
应用:关键路径
拓扑排序的定义:在AOV网没有回路的前提下,我们将全部活动排列成一个线性序列,使得若AOV网中有弧存在,则在这个序列中,i 一定排在 j 的前面,具有这种性质的线性序列称为拓扑有序序列,相应的拓扑有序排序算法称为拓扑排序。
拓扑排序流程
在有向网中选择一个没有前驱的顶点并将其依次添加到拓扑序列中。
从图中删除该顶点和所有以它为尾的弧。
重复上述两个步骤,直至将全部顶点添加进拓扑序列,或者图中不存在无前驱的顶点为止。
检测AOV网中是否存在环的方法
对有向图构造其顶点的拓扑有序序列,若网中所有顶点都在它的拓扑有序序列中,则该AOV网必定不存在环。
C语言应用举例
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* findOrder(int numCourses, int** prerequisites, int prerequisitesSize, int* prerequisitesColSize, int* returnSize){
int* ret = (int*)malloc(sizeof(int)*numCourses);
//计算每门课的入度
int* inDegree = (int*)malloc(sizeof(int)*numCourses);
for(int i = 0; i < numCourses; i++){
inDegree[i] = 0;
}
for(int i = 0; i < prerequisitesSize; i++){
int a = prerequisites[i][0];
inDegree[a]++;
}
//拓扑排序
*returnSize = 0;
int* queue = (int*)malloc(sizeof(int)*numCourses+1);
int front = 0, rear = 0;
for(int i = 0; i < numCourses; i++){
if(inDegree[i] == 0){ //将入度为0的节点入队
queue[rear] = i;
rear = (rear+1)%(numCourses+1);
}
}
while(rear != front){
//出队
int cur = queue[front];
ret[*returnSize] = cur;
(*returnSize)++;
front = (front+1)%(numCourses+1);
//调整子节点的入度并将入度为0的节点入队
for(int i = 0; i < prerequisitesSize; i++){
int a = prerequisites[i][1], b = prerequisites[i][0];
if(a == cur){
inDegree[b]--;
if(inDegree[b] == 0){
queue[rear] = b;
rear = (rear+1)%(numCourses+1);
}
}
}
}
free(inDegree);
if(*returnSize != numCourses)*returnSize = 0;
return ret;
}