目录
前言
一、拓扑排序
二、关键路径
总结
前言
一个无环的有向图称为有向无环图,简称DAG图。
有向无环图也是描述一项工程或系统的进行过程的有效工具。
解决的实际问题:
1.一是工程能否顺利进行;------------------------ 拓扑排序
2.二是估算整个工程完成所必须的最短时间。 ---------关键路径
一、拓扑排序
1.什么是拓扑排序?
由某个集合上的一个偏序得到该集合上的一个全序的操作称之为拓扑排序。
***回顾***
偏序:若集合X上的关系R是自反的、反对称的和传递的,则称R是集合X上的偏序关系。
全序:设R是集合X上的偏序,如果对每个x,yX必有xRy或yRx,则称R是集合X上的全序关系。
直观地看,偏序指集合中仅有部分成员之间可比较,而全序指集合中全体成员之间均可比较。
偏序
全序
2.如何进行拓扑排序?
(1)在有向图中选一个没有前驱的顶点切输出之;
(2)从图中删除该顶点和所有以它为尾的弧。
重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止。
a
b
c
d
e
f
该有向图的拓扑有序序列为:
3.如何在计算机中实现?
针对上述两步操作,我们可采用邻接表作有向图的存储结构,且在头结点中增加一个存放顶点入度的数据域(indegree)。入度为零的顶点即为没有前驱的顶点,可查找表头向量求得;至于删除顶点及以它为尾的弧的操作,则可换以弧头顶点的入度减1来实现。
图a的邻接表
4.数据结构设计
建立一个记录入度为0的顶点的链式栈
//建立一个记录入度为0的顶点的链式栈
typedef struct arcnode
{
int adjvex;
arcnode* nextarc;
}* pointer;//表结点
struct node
{
char vexdata;
int id;//顶点的入度
pointer firstarc;
}dig[100];//一组头结点
5.拓扑排序算法思想
(1)建立入度为零的顶点栈;
(2)当入度为零的顶点栈不空时,重复执行:
(2)-1 从顶点栈中退出一个顶点,并输出之;
(2)-2 从AOV网络中删去这个顶点和它发出的边,边的终顶点入度减1;
(2)-3 如果边的终顶点入度减至0,则该顶点进入度为零的顶点栈;
(3)如果输出顶点个数少于AOV网络的顶点个数,则报告网络中存在有向环。
标拓扑排序过程中入度域的变化过程示例
(a)邻接表建成后的状态;(b)进行拓扑排序之前的状态;
(c) V6出栈之后的状态; (d)输出V1之后的状态;
(e)输出V3之后的状态; (f)V2出栈之后的状态;
//拓扑排序算法实现
void toposort()
{
inistack(s);//置空栈
for(i=1;i<=n;i++)
if(dig[i].id==0)
push(s.i);//入度为0的顶点栈
count=0;//count为计数器,计输出顶点数
while(!stackempty(s))
{
j=pop(s);
printf(dig[j].vexdata);
count++;
q=dig[j].firstarc;//q指示以vj为尾第一条弧结点
while(q)
{
k=q->adjvex;//顶点vk为vj的直接后继
dig[k].id--;
if(dig[k].id==0)
push(s,k);//新的入度为0的顶点入栈
q=q->nextarc;
}
}
if(count<n)
error("该图中存在回路");
}
6.算法分析
对于有n个顶点和e条弧的有向图而言,建立邻接表的时间为O(n+e);搜索入度为0的时间为O(n);在拓扑排序中,若有向图无环,则每个顶点进一次栈,出一次栈,入度减1的操作总共执行e次;总的时间复杂度为O(n+e)。