数据结构--图(拓扑排序)

拓扑排序

应用对象:有向无环图(DAG)

AOV网:用一个有向图表示一个工程的各个子工程及其相互制约的关系,以顶点表示活动,弧表示活动之间的优先制约关系,称这种有向图为顶点表示活动的网,简称AOV网。

应用:拓扑排序

AOE网:用一个有向图表示一个工程的各个子工程及其相互制约的关系,以弧表示活动,以顶点表示活动开始或结束事件,称这种有向图为边表示活动的网,简称AOE网。

应用:关键路径

拓扑排序的定义:在AOV网没有回路的前提下,我们将全部活动排列成一个线性序列,使得若AOV网中有弧存在,则在这个序列中,i 一定排在 j 的前面,具有这种性质的线性序列称为拓扑有序序列,相应的拓扑有序排序算法称为拓扑排序。

拓扑排序流程

  • 在有向网中选择一个没有前驱的顶点并将其依次添加到拓扑序列中。

  • 从图中删除该顶点和所有以它为尾的弧。

  • 重复上述两个步骤,直至将全部顶点添加进拓扑序列,或者图中不存在无前驱的顶点为止。

检测AOV网中是否存在环的方法

对有向图构造其顶点的拓扑有序序列,若网中所有顶点都在它的拓扑有序序列中,则该AOV网必定不存在环。

C语言应用举例

题目来源:leetcode 210.课程表II

/**
 * 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;
}

你可能感兴趣的:(数据结构--图(拓扑排序))