有向无环图:无环的有向图,简称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;
}