有向无环图的应用之拓扑排序(C语言)

本文介绍了有向无环图(DAG)的概念,以及它在工程流程和活动制约中的应用。AOV网和AOE网分别用于表示活动的顶点和边,拓扑排序用于确定活动的顺序。拓扑排序算法通过寻找无前驱顶点并输出,直至所有顶点输出或发现环。文中还给出了拓扑排序的C语言实现示例。
摘要由CSDN通过智能技术生成

有向无环图:无环的有向图,简称DAG图(Directed Acycline Gragh),不存在回路

有向无环图常用来描述一个工程或系统的进行过程.(通常把计划,施工,生产,程序流程等当成是一个工程)

一个工程可以分为若干个子工程,只要完成了这些子工程(活动),就可以使整个工程完成.

AOV网:

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

AOE网:

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

AOV网用来解决拓扑排序问题,AOE网用来解决关键路径问题

拓扑排序:

AOV网的特点:1,若从i到j有一条有向路径,则i是j的前驱;j是i的后继

2,若<i,j>是网中有向边,则i是j的直接前驱,j是i的直接后继.

拓扑排序定义

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

拓扑排序的方法

1,在有向图中选一个没有前驱的顶点且输出之.

2,从图中删除该顶点和所有以它为尾的弧.

3,重复上述两步,直至全部顶点均已输出;或者当图中不存在无前驱的顶点为止.

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

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

举个例子:

你可以把下面的123456想象成过关游戏的123456关,只有过了第1关才能进行第2关,过了第2关才能进行第3关一直到第6关.

也可以把123456想象成读书的123456年级,只有读了1年级才能进入2年级,这些顶点之间的制约关系就是这样的.

我们来构造上面有向图的拓扑序列:首先找到没有前驱的顶点 1,输出,然后删除该顶点和所有以它为尾的弧.

 

重复上面的步骤:

 

  

 所以,它的拓扑序列为:1 2 3 4 5 6

而且从上面例子可以看出,拓扑序列在有的情况下并不是唯一的,可以有不同的排列.

下面就拓扑排序算法C语言的实现:

实现思路:

1,找到没有前驱的顶点

        我们用邻接矩阵保存有向图,不难发现,没有前驱的顶点的特点就是,矩阵中顶点代表的那一列数据,没有变动,初始化成什么,就是什么.

2,删除该顶点和所有以它为尾的弧.

        从矩阵中发现,要删除该顶点和所有以它为尾的弧,只要把该顶点的列和行,从矩阵中去除掉就可以了,也可以在访问该矩阵的时候跳过该顶点所在的行和列.

下面我们就来实现他,要实现拓扑排序有很多方法:有利用栈的深度优先DFS算法利用队列的广度优先算法BFS,还有最普通的利用邻接矩阵的方法.前面两种方法,网上很多,我这里就用邻接矩阵的方法来实现:

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 15
#define MAXINT 10000
int get_index(int* arr, int e)//得到输出的顶点,在数组中的下标
{
    int i = 0;
    for(i = 0; i < MAXSIZE; i++)
    {
        if(arr[i] == e)return i;
    }
    return -1;
}

void TopologicalSorting(int arcs[][MAXSIZE])
{
    int m,n,i,j,a,b;
    int vertex[MAXSIZE] = {0};//初始化顶点数组
    int visited[MAXSIZE] = {0};
    printf("请输入顶点数和弧的数目:>");
    scanf("%d%d",&m,&n);
    for(i = 0; i < m; i++)
    {
        printf("请输入每一个顶点:>");
        getchar();
        scanf("%d", &vertex[i]);
    }
    for(j = 0; j < n; j++)
    {
        printf("请输入每一条边:>");
        getchar();
        scanf("%d%d",&a,&b);
        arcs[get_index(vertex,a)][get_index(vertex,b)] = 1;//根据输入更新邻接矩阵
    }
    int num = 0;
    while(num != m)//找到全部顶点就结束
    {
        for(i = 0; i < m; i++)//循环遍历邻接矩阵
        {
            for(j = 0; j < m; j++)
            {
                //如果找到某一列的数据全部为0,说明这一列所代表的顶点是没有前驱的
                //这里visited[j],是用来限制某一行,visited[i]为限制某一列
                if((arcs[j][i] == 1 && !visited[j]) || visited[i])break;
            }
            if(j == m)
            {
                printf("%d",vertex[i]);//输出没有前驱的顶点
                num++;//找到的顶点数加1
                visited[i] = 1;//设置这个顶点为已访问
            }
        }
    }

}


int main()
{
    int arcs[MAXSIZE][MAXSIZE]={{0}};//邻接矩阵
    TopologicalSorting(arcs);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值