【数据结构】图论

本文深入探讨了图论中的重要算法,包括AOV网的拓扑排序用于判断有向图是否存在回路,AOE网的关键路径计算以确定工程最短完成时间,以及普利姆和克鲁斯卡尔算法求解图的最小代价生成树。这些算法在实际问题中有着广泛应用,如项目管理、网络设计等。
摘要由CSDN通过智能技术生成

数据结构图论部分知识点总结:

第9章 图论

一、AOV网

AOV网:一个有向无环图。含义是用AOV网表示各个事件的先后关系,对于每一条边,终点(弧尾)以始点(弧尾)为先决条件,而一个点不可能以自己为先决条件。

1.拓扑排序

拓扑排序生成的拓扑序列可以用来检测一个有向图是不是AOV网,即判断该有向图有没有回路。

(1)内容:
  • 对于一个n个点,e条边的图,任选入度为0的点输出,

  • 然后删除该点即所有出边。

  • 重复直至没有入度为0的边

    ① 输出的顶点数 < 总顶点数:存在有向回路,不是AOV网。
    ② 输出的定点数 > 总顶点数:不存在有向回路,是AOV网,此时输出的序列为拓扑序列。

(2)算法设计:
  • 定义 邻 接 表 \textcolor{red}{邻接表} 作为图的存储结构。
  • 定义inDegree数组存储所有顶点的入度。

初始化操作可以循环遍历邻接表统计所有顶点的入度。

  • 定义topo数组存储输出的拓扑序列。
  • 定义一个存储所有顶点入度为0的顶点,包括新出现的入度为0的顶点。

每删除一个点和边(对该点邻接到的点入度减一),然后检测删除点的邻接点的入度,入度为0就入栈。

  • 对入度为0的顶点的选择可以通过出栈操作实现。出栈前先检测栈是否为空,即当前有无入度为0的顶点,没有就结束拓扑排序。
(3)时间复杂度

O ( n + e ) O(n+e) O(n+e)

二、AOE网及关键路径

AOE网:把一个工程看作一个AOE网。一个AOE网是一种特殊的AOV网。

  • 有且仅有一个入度为0的点,称为源点(工程的开始)。
  • 有且仅有一个出度为0的点,称为汇点(工程的结束)。
  • 不存在回路。(无环)
  • 且每条边都带权的有向图。

关键路径:从源点到汇点的最长路径。代表一个工程的最短完成时间

1.关键路径的求解步骤

(1)对AOE网进行拓扑排序

(2)用下列公式按拓扑序列求出每个 事 件 \textcolor{red}{事件} 可能的最早发生时间 E e a r l y ( v i ) E_{early}(v_i) Eearly(vi)

x = { E e a r l y ( v 0 ) = 0 E e a r l y ( v j ) = m a x { E e a r l y ( v i ) + w ( v i , v j ) } 0 < j < n x = \begin{cases}E_{early}(v_0)=0\\E_{early}(v_j)=max\text\{E_{early}(v_{i})+w(v_i,v_j)\}&0<j<n\end{cases} x={Eearly(v0)=0Eearly(vj)=max{Eearly(vi)+w(vi,vj)}0<j<n

(3)用下列公式按逆拓扑序列(即从后往前)和 E e a r l y ( 汇 点 ) E_{early}(汇点) Eearly()求出每个 事 件 \textcolor{red}{事件} 允许的最迟发生时间 E l a t e ( v i ) E_{late}(v_i) Elate(vi)

x = { E l a t e ( v n − 1 ) = E e a r l y ( v n − 1 ) E l a t e ( v i ) = m i n { E l a t e ( v j ) − w ( v i , v j ) } 0 ≤ i < n − 1 } x = \begin{cases}E_{late}(v_{n-1})=E_{early}(v_{n-1})\\E_{late}(v_i)=min\text\{E_{late}(v_{j})-w(v_i,v_j)\}&0\leq i<n-1\}\end{cases} x={Elate(vn1)=Eearly(vn1)Elate(vi)=min{Elate(vj)w(vi,vj)}0i<n1}

(4)求出每个 活 动 \textcolor{red}{活动} 可能的最早开始时间 A e a r l y ( a k ) A_{early}(a_k) Aearly(ak)

A e a r l y ( a k ) = E e a r l y ( v i ) A_{early}(a_{k})=E_{early}(v_i) Aearly(ak)=Eearly(vi),其中ak关联vi和vj

(5)求出每个 活 动 \textcolor{red}{活动} 允许的最迟开始时间 A l a t e ( a k ) A_{late}(a_k) Alate(ak)

A l a t e ( a k ) = E l a t e ( v j ) − w ( v i , v j ) A_{late}(a_{k})=E_{late}(v_j)-w(v_{i},v_{j}) Alate(ak)=Elate(vj)w(vi,vj),其中ak关联vi和vj

(6)找出 A e a r l y ( a k ) = A l a t e ( a k ) A_{early}(a_k)=A_{late}(a_k) Aearly(ak)=Alate(ak)的活动ak即为关键活动,由关键活动形成的由源点到汇点的路径即为关键路径

2.关键路径算法

(1)算法实现
  • 用一个数组存储可能最早发生时间,遍历拓扑序列,每次更新数组元素值
  • 另一个数组存储允许最迟发生时间,遍历逆拓扑序列,每次更新数组元素值
(2)时间复杂度

O ( n + e ) O(n+e) O(n+e)

二、图的最小代价生成树

  • n个顶点的无向连通图最少有n-1条边。
  • 生成树:n个顶点的无向连通图的生成树是一棵极小连通子图,包括该图中的所有顶点,有足以构成一棵树的n-1条边

一个带权图的各生成树中,具有最小代价的生成树(各边上的代价之和)称为该网络的最小代价生成树。关于如何构造最小代价生成树有普利姆算法布鲁斯卡尔算法

1.普利姆算法

(1)内容:

G为含n个顶点的带权连通网,T是正在构造中的生成树(初始状态下T只有一个任选的起始顶点,且无边),从初始状态开始,重复执行下列运算:

①从T的入边中找一条代价最小的边e(出现多条时任选其一)

②将e及其不属于T的那个顶点加入T;

③重复(1)(2)直至所有顶点加入T。
在这里插入图片描述

在这里插入图片描述

(2)算法设计:

所需数据结构如下:

  • 图采用 邻 接 表 \textcolor{red}{邻接表} 存储
  • 定义一维数组nearest[]lowcost[]mark[],并初始化,

其中nearest[i]存放当前生成树中与顶点i距离最近的顶点,lowcost[i]存放边(i,nearest[i])的权值,mark[i]标记顶点i是否已经在生成树上。
初始状态下nearest数组中的元素置为-1,lowcost数组中的元素置为INFTY(一个极大值),mark数组所有元素置TRUE。

  • 初始顶点加入生成树T。

  • 对于尚未在生成树中的顶点v,如果(u,v)是v与生成树T中若干顶点构成的边中权值最小的,则设置nearest[v]=u,lowcost[v]=w(u,v)。

生成树每新加入一个点就要对新加入的点遍历其边链表,将其和树外点间的权值与对应的lowcost值作比较,更新nearest[v]和lowcost[v]

  • mark[v]=True代表v加入了生成树。
(3)时间复杂度:

O ( n 2 ) O(n^{2}) O(n2)

2.克鲁斯卡尔算法

(1)内容:

T:正在构造中的生成树。
G:图
E:图的边集合
E’:生成树的边集合

从初始状态(此时T中只包含G中所有顶点,无边)开始,重复执行下列运算:

①在E中选择一条代价最小的边(u,v), 并将其从E中删除,加入T;

②若在生成树的边集合E’中加入边(u,v)以后未形成回路,则将其加进E’中,否则继续从E中选择下一条边;

③重复执行步骤② ,直至E’中包含n-1条边时为止

(2)算法设计:

所需数据结构如下:

  • 图采用 邻 接 矩 阵 \textcolor{red}{邻接矩阵} 存储
  • 一维结构体数组edgeSet[]用于存储图中所有边的信息,包括边的两个顶点和边的权值,edgeSet[i]存放图中的一条边。
  • 一维数组vexSet[]用于标识各顶点所属的连通分量,其中vexSet[i]表示顶点i所属连通分量,初始时vexSet[i]=i,表示自身构成一个连通分量。

关键步骤:

  • 从邻接矩阵获取所有边存入edgeSet
  • 用排序算法对edgeSet中的边按权值从小到大排列选出
  • 用数组vexSet[]存储各点所属联通分量,选择权值最小的边插入T,并判断两个边的顶点uv是否在一个连通分量即vexSet[u]和vexSet[v]是否相等,
    • vexSet[u]!=vexSet[v],不会形成回路,然后合并这两个连通分量
    • vexSet[u]==vexSet[v],形成回路,选择次小继续判断。
(3)时间复杂度:

O ( e ∗ l o g 2 e ) O(e*log_2e) O(elog2e)

三、图的单源最短路径

1.迪杰斯特拉算法

(1)算法设计

所需数据结构如下:

  • 采用邻接矩阵存储
  • s[]记录对应下标的顶点是否在S集合中,即是否确定最短路径。
  • d[]存放v0到下标对应点的当前最短路径的长度(注意:这里的d[]存放的最短路径值跟最后的不一定一致)
  • path[]存储下标对应顶点的前驱结点。

主要步骤:

  • 先初始化数组值。

    s[0]置1,其余为0。

    d[i]如果v0到顶点vi存在边则置权值,不存在边则置无穷大的数。

    path[i]如果v0到顶点vi存在边则置0,不存在边则置-1。

  • 循环选出最小的d[k],得到对应k,置s[k]=1,进入下一轮选择前要先更新d[w](w是V-S集合中的某个点)的值,循环遍历当前V-S集合中的各个点,比较d[k]+w[k][w]与d[w]的大小,小的那个录入d[w],还要更新path[w]。

(2)时间复杂度
  • O ( n 2 ) O(n^2) O(n2)

  • 求源点到某一顶点间的最短路径: O ( n 2 ) O(n^2) O(n2)

  • 求任意两对顶点间的最短路径(每次选一个顶点为源点重复n次): O ( n 3 ) O(n^3) O(n3)

w[k][w]与d[w]的大小,小的那个录入d[w],还要更新path[w]。

四、总结:

拓扑排序求关键路径普利姆算法克鲁斯卡尔算法迪杰斯特拉算法
图的存储结构邻接表邻接表邻接表 邻 接 矩 阵 \textcolor{red}{邻接矩阵} 邻 接 矩 阵 \textcolor{red}{邻接矩阵}
算法用到的数据结构数组、 栈 \textcolor{red}{栈} 数组数组结构体数组数组
时间复杂度 O ( n + e ) O(n+e) O(n+e) O ( n + e ) O(n+e) O(n+e) O ( n 2 ) O(n^2) O(n2) O ( e l o g 2 e ) O(elog_2e) O(elog2e) O ( n 2 ) O(n^2) O(n2)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Em0s_Er1t

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

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

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

打赏作者

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

抵扣说明:

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

余额充值