【数据结构学习记录22】——有向无环图及其应用

本文介绍了有向无环图(DAG)的概念及其在拓扑排序和关键路径分析中的应用。详细阐述了拓扑排序的过程与偏序、全序的区别,并通过实例说明了如何在AOE网中找到关键路径。

一.有向无环图的概念

一个无环有向图称作有向无环图。简称DAG图DAG图是相较于有向树的更特殊的图。比如:

检查一个图是否有环,可以通过遍历+标记的方式进行检查,若某个顶点的弧指向了另一个已经遍历过的顶点,则该图必定含有环。

二.拓扑排序(AOV网)

1.概念

来自百度:

对一个 有向无环图 (Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个 偏序 得到该集合上的一个 全序 ,这个操作称之为拓扑排序。

2.偏序与全序

定义可以自己百度,这里记一下我对于这个偏序与全序的理解。

a).偏序

在这里插入图片描述

偏序里的集合的成员,只能部分的访问到,存在某个顶点,无法通过其指向访问的顶点,比如这个图,V2 无法访问到 V3, V3无法访问到V2 。V1可以通过指向V2指向V4访问到V4。

b).全序

在这里插入图片描述

全序是指,所有的成员都可以互相比较。
比如这个图,图中任意两个顶点,都是可以从图中找到一条以上的通路而访问到。

c).偏序与全序的区别

用具体例子来说,偏序可以表示为某些科目依赖关系,而全序可以理解为设计出来的学习计划。
举个例子:偏序表告诉我们学习控制理论需要先学习高数1、2和信号与系统,信号与系统需要先学习高数1,2。
那么全序就是我们的学习计划:先学习高数1,再学习高数2,再学习信号与系统,再学习控制理论。

3.拓扑有序

如果我们通过自己添加弧来使得一个偏序变成全序,那么这个操作就是拓扑排序而这个全序被称作拓扑有序
某个偏序的拓扑有序是不唯一的:排序的方式不同,所以人为添加的弧的方式也不同,所以一个偏序的拓扑有序是不唯一的,它会有多个。

4.拓扑排序的过程

  1. 再有向图中,选择一个没有前驱的顶点且输出。
  2. 从图中删除该顶点和它为尾的弧。
  3. 重复1、2直到所有的顶点都已输出,或当前图中不存在无前驱的顶点为止(有环)。

三.关键路径(AOE网)

1.概念

AOE 网是在 AOV 网的基础上,其中每一个边都具有各自的权值,是一个有向无环网。其中权值表示活动持续的时间。
所以我们AOE网的建立至少要满足拓扑有序
使用 AOE 网可以帮助解决这样的问题:如果将 AOE 网看做整个项目,那么完成整个项目至少需要多少时间?
解决这个问题的关键在于从 AOE 网中找到一条从起始点到结束点长度最长的路径,这样就能保证所有的活动在结束之前都能完成。
起始点是入度为 0 的点,称为“源点”;结束点是出度为 0 的点,称为“汇点”。这条最长的路径,被称为”关键路径“。
为了求出一个给定 AOE 网的关键路径,需要知道以下 4 个统计数据:

  1. 对于 AOE 网中的顶点有两个时间:最早发生时间(用 Ve(j) 表示)和最晚发生时间(用 Vl(j) 表示);
  2. 对于边来说,也有两个时间:最早开始时间(用 e(i) 表示)和最晚开始时间( l(i) 表示)。

2.实现

对照这个图来讲:
在这里插入图片描述

a).最早发生时间Ve(j)

这里的最早发生时间,实际上是事件最早能多久开始,也就是前面的时间路线的最长的那一条,就比如你要沏茶肯定得水先烧好,就算把茶叶放进去了你还是得等水。
Ve(j):对于 AOE 网中的任意一个顶点来说,从源点到该点的最长路径代表着该顶点的最早发生时间,通常用 Ve(j) 表示。
例如,图 1 中从 V1 到 V5 有两条路径,V1 作为源点开始后,a1 和 a2 同时开始活动,但由于 a1 和 a2 活动的时间长度不同,最终 V1-V3-V5 的这条路径率先完成。但是并不是说 V5 之后的活动就可以开始,而是需要等待 V1-V2-V5 这条路径也完成之后才能开始。所以对于 V5 来讲,Ve(5) = 7。
在这里插入图片描述

b).最晚发生时间Vl(j)

还是用泡茶的例子,因为烧水需要一定的时间,所以放茶叶并不需要在刚烧水就开始,也可以在水开之前开始,后者就是我们的最晚发生时间。
Vl(j):表示在不推迟整个工期的前提下,事件 Vk 允许的最晚发生时间。
例如,在得知整个工期完成的时间是 18 天的前提下,V7 最晚要在第 16 天的时候开始,因为 a10 活动至少需要 2 天时间才能完成,如果在 V7 事件在推迟,就会拖延整个工期。所以,对于 V7 来说,它的 Vl(7)=16。
在这里插入图片描述

c).e(i)

表示活动 ai 的最早开始时间,如果活动 ai 是由弧 <Vk,Vj> 表示的,那么活动 ai 的最早开始的时间就等于时间 Vk 的最早发生时间,也就是说:e[i] = ve[k]
在这里插入图片描述

d).l(i)

l(i):表示活动 ai 的最晚开始时间,如果活动 ai 是由弧 <Vk,Vj> 表示,ai 的最晚开始时间的设定要保证 Vj 的最晚发生时间不拖后。所以,l[i]=Vl[j]-len<Vk,Vj>
在这里插入图片描述

四.代码

1.AOV

在这里插入图片描述

样例输入与输出:

please input the number of Vertex and Arc:6 8
please input Vertexs' name:
123456
please input (tail,head) as the arc:
0 1
0 2
0 3
2 1
2 4
3 4
5 3
5 4

No.0 inArc:0 Vex:1 to 2 3 4 
No.1 inArc:2 Vex:2 to       
No.2 inArc:1 Vex:3 to 2 5   
No.3 inArc:2 Vex:4 to 5
No.4 inArc:3 Vex:5 to
No.5 inArc:0 Vex:6 to 4 5

One AOV is: 6 1 4 3 5 2

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define         OK          1
#define         ERROR       0
#define         MaxLen      100

typedef struct ArcNode{
   
   
    int Head;
    struct ArcNode *nextArc;
}ArcNode;   // 创建弧结点

typedef struct VNode{
   
   
    char NodeName;
    int inNum;
    ArcNode *nextArc;
}VNode;     // 创建Vertex顶点结点

typedef struct Graph{
   
   
    int len;
    VNode *Nbase;   // 线性存储顶点结点
}Graph;     // 创建一张图

int MarkGraph[MaxLen];  // 标记数组

Graph *GraphCreat(void);
int GraphShowList(Graph *G);
int GraphShowAOV(Graph *G);

int main()
{
   
   
    Graph *map = GraphCreat();
    GraphShowList(map);
    GraphShowAOV(map);
    return 0;
}

Graph *GraphCreat(void)
{
   
   
    Graph *G = (Graph*)malloc(sizeof(Graph));
    int lenV, lenA;
    int i, tail, head;
    char chname[MaxLen];
    char temp;
    ArcNode *ArcNow, *ArcLast;

    printf("please input the number of Vertex and Arc:");
    scanf("%d %d", &lenV, &lenA);   // 获取 顶点数和弧的个数

    if (lenV > MaxLen)
    {
   
   
        printf("Over MaxLenth");
        exit(ERROR);
    }   // 限制下大小

    // 创建顶点线性表
    G->len = lenV;
    G->Nbase = (VNode*)malloc(sizeof(VNode)*lenV);
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

康娜喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值