图的知识梳理

本文介绍了图的定义,包括无向图、有向图、完全图和稀疏图的概念,以及顶点的度、路径、回路等术语。接着,讨论了图的两种存储结构——邻接矩阵和邻接表,分析了它们的优缺点。此外,文章详细阐述了深度优先遍历(DFS)和广度优先搜索(BFS)的原理和实现。最后,提到了图的应用,如最小生成树、最短路径和拓扑排序问题。
摘要由CSDN通过智能技术生成

图的定义和术语

:Graph=(V,E)
⭐️V:顶点(数据元素)的有穷非空集合;
⭐️E:边或弧的有穷集合

无向图:每条边都是无方向的
有向图: 每条边都是有方向的,叫做弧
完全图: 任意两个点都有一条边相连
在这里插入图片描述
**稀疏图:**有很少边或弧的图(如e<nlogn)
**稠密图:**有较多边或弧的图
网:边/弧带权的图
邻接有边/弧相连的两个顶点之间的关系。
存在(vi, vj)
(无向)
,则称vi和vj互为邻接点;存在<vi, vj>(有向),则称vi邻接到vj, vj邻接于vi

关联(依附) 边/弧与顶点之间的关系。
存在(vi, vj)/ <vi, vj>, 则称该边/弧关联于vi和vj

顶点的度
⭐️与该顶点相关联的边的数目,记为TD(v)
⭐️在有向图中, 顶点的度等于该顶点的入度与出度之和。
⭐️顶点 v 的入度是以 v 为终点的有向边的条数, 记作 ID(v)
⭐️顶点 v 的出度是以 v 为始点的有向边的条数, 记作OD(v)

当有向图中仅1个顶点的入度为0,其余顶点的入度均为1,此时是何形状?

是树!而且是一颗有向树!

路径:接续的边构成的顶点序列。
**路径长度:**路径上边或弧的数目/权值之和
**回路(环):**第一个顶点和最后一个顶点相同的路径。
**简单路径:**除路径起点和终点可以相同外,顶点不相同的路径。
**简单回路(简单环):**除路径起点和终点相同外,其余顶点均不相同的路径
在这里插入图片描述

子图设有两个图G=(V,{E})、G1=(V1,{E1}),若V1⊆ V,E1 ⊆ E ,则称 G1是G的子图。
连通图(强连通图) 在无(有)向图G=( V, {E} )中,若对任何两个顶点 v、u 都存在从v 到 u 的路径,则称G是连通图(强连通图)。
在这里插入图片描述
连通分量(无向图)
⭐️无向图G 的极大连通子图称为G的连通分量。
⭐️极大连通子图意思是: 该子图是 G 连通子图,将G 的任何不在该子图中的顶点加入,子图不再连通。
在这里插入图片描述

强连通分量(有向图)
⭐️有向图G 的极大强连通子图称为G的强连通分量。
⭐️极大强连通子图意思是: 该子图是G的强连通子图,将D的任何不在该子图中的顶点加入,
子图不再是强连通的。
在这里插入图片描述
极小连通子图
该子图是G 的连通子图,在该子图中删除任何一条边,子图不再连通。

在这里插入图片描述
生成树:
包含无向图G 所有顶点的极小连通子图。
连通图中由 n 个顶点和 n-1 条边构成的极小连通子图
在这里插入图片描述

↓(包含所有顶点的极小连通子图可转化文如下的树)

在这里插入图片描述

生成森林:
对非连通图,由各个连通分量的生成树的集合

练习
若一个无向图有n个顶点和n条边,则这个图一定是()
🙇有环的

结论:顶点数为n的无向图
边小于n-1,非连通图
边大于n-1,一定有环

若无向图G=(V,E)中含有7个顶点,要保证图G在任何情况下都是连通的,则需要的边数最少为
🙇16

6个顶点构成完全无向图,共15条边,再加一条连接第七个顶点

一个有28条边的非连通无向图至少有()个顶点
🙇9

最极端情况:完全无向图+一个顶点

对于n个顶点的图,若是连通无向图,边个数至少为(),
若是强连通有向图,边个数至少为()

连通无向图边最少:生成树,n-1
强连通有向图边最少:有向环,n

已知无向图G含有16条边,度为4的顶点个数为3,度为3的顶点个数为4,其余顶点度均小于3,问图G所含顶点个数至少是

🙇11

无向图各顶点度数总和等于边的二倍。

图的存储结构

数组(邻接矩阵)表示法

建立一个顶点表(记录各个顶点信息)和一个邻接矩阵(表示各个顶点之间关系)。
设图 A = (V, E) 有 n 个顶点,则图的邻接矩阵是一个二维数组 A.Edge[n][n],定义为:
在这里插入图片描述
无向图
在这里插入图片描述

分析1:无向图的邻接矩阵是对称的;
分析2:顶点i 的度=第 i 行 (列) 中1 的个数;
特别:完全图的邻接矩阵中,对角元素为0,其余1

有向图

在这里插入图片描述

注:在有向图的邻接矩阵中,第i行含义:以结点vi为尾的弧(即出度边);第i列含义:以结点vi为头的弧(即入度边)。
分析1:有向图的邻接矩阵可能是不对称的。
分析2:顶点的出度=第i行元素之和;顶点的入度=第i列元素之和
顶点的度=第i行元素之和+第i列元素之和

网(有权图)
在这里插入图片描述
在这里插入图片描述
邻接矩阵表示法的特点

优点:容易实现图的操作,如:求某顶点的度、判断顶点之间是否有边、找顶点的邻接点等等。
缺点:n个顶点需要n*n个单元存储边;空间效率为O(n2)。 对稀疏图而言尤其浪费空间。

邻接表表示法(链式)

顶点:
按编号顺序将顶点数据存储在一维数组中;
关联同一顶点的边(以顶点为尾的弧):
用线性链表存储
在这里插入图片描述
头结点
在这里插入图片描述
表结点
在这里插入图片描述
无向图的邻接表
在这里插入图片描述

注:邻接表不唯一,因各个边结点的链入顺序是任意的
空间效率为O(n+2e)。
若是稀疏图(e<<n2),比邻接矩阵表示法O(n2)省空间。
TD(Vi)=单链表中链接的结点个数

有向图
在这里插入图片描述

空间效率为O(n+e)
出度:OD(Vi)=单链出边表中链接的结点数
入度:ID(Vi)=邻接点域为Vi的弧个数

邻接表表示法的特点

优点:空间效率高,容易寻找顶点的邻接点;
缺点:判断两顶点间是否有边或弧,需搜索两结点对应的单链表,没有邻接矩阵方便。

图的遍历

遍历定义:从已给的连通图中某一顶点出发,沿着一些边访遍图中所有的顶点,且是每一个顶点仅被访问一次,就叫做图的遍历,他是图的基本运算。

遍历实质:找每个顶点的邻接点的过程。

深度优先遍历(DFS)

1、从图中某个顶点V1 出发,访问此顶点
2、然后依次从V1的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和V1 有路径相通的顶点都被访问到。
3、若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。

在这里插入图片描述
详细过程
在访问图中某一起始顶点 v 后,由 v 出发,访问它的任一邻接顶点 w1;
再从 w1 出发,访问与 w1邻接但还未被访问过的顶点 w2;
然后再从 w2 出发,进行类似的访问,…
如此进行下去,直至到达所有的邻接顶点都被访问过的顶点 u 为止
接着,退回一步,退到前一次刚访问过的顶点,看是否还有其它没有被访问的邻接顶点。
如果有,则访问此顶点,之后再从此顶点出发,进行与前述类似的访问;
如果没有,就再退回一步进行搜索。重复上述过程,直到连通图中所有顶点都被访问过为止

如何判别V的邻接点是否被访问?
解决的办法是:为每个顶点设立一个 “访问标志 visited[w]”

在这里插入图片描述
深度优先遍历算法

void DFS(Graph G, int v) {
   // 从顶点v出发,深度优先搜索遍历连通图 G
    visited[v] = TRUE;   VisitFunc(v);
    for(w=FirstAdjVex(G, v);w>=0; w=NextAdjVex(G,v,w))
        if (!visited[w])  DFS(G, w);     
              // 对v的尚未访问的邻接顶点w
              // 递归调用DFS
} // DFS

DFS算法效率分析
1、用邻接矩阵来表示图,遍历图中每一个顶点都要从头扫描该顶点所在行,时间复杂度为O(n2)。
2、用邻接表来表示图,虽然有 2e 个表结点,但只需扫描 e 个结点即可完成遍历,加上访问 n个头结点的时间,时间复杂度为O(n+e)。

广度优先搜索(BFS)

详细过程
从图中的某个顶点V1出发,并在访问此顶点之后依次访问V1的所有未被访问过的邻接点,之后按这些顶点被访问的先后次序依次访问它们的邻接点,直至图中所有和V1 有路径相通的顶点都被访问到
若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。

算法思想
从图中某个顶点v出发,访问v,并置visited[v]的值为true,然后将v进队。
只要队列不空,则重复下述处理
① 队头顶点u出队。
② 依次检查u的所有邻接点w,如果visited[w]的值为false,则访问w,并置visited[w]的值为true,然后将w进队。

🙇代码实现

void BFSTraverse(Graph G,Status (*Visit)(int v)){
   for (v=0; v<G.vexnum; ++v)
       visited[v] = FALSE;  //初始化访问标志
   InitQueue(Q);       // 初始化空的辅助队列Q
   for ( v=0;  v<G.vexnum;  ++v )
      if ( !visited[v]) {          // v 尚未访问
      visited[v] = TRUE;    Visit(v);    // 访问v
	EnQueue(Q, v);             // v入队列
	while (!QueueEmpty(Q))  {
   DeQueue(Q, u);        // 队头元素出队并置为u
   for(w=FirstAdjVex(G, u); w!=0; w=NextAdjVex(G,u,w))
      if ( ! visited[w])  {
         visited[w]=TRUE;   Visit(w);
         EnQueue(Q, w); // 访问的顶点w入队列

    } //if
  } // BFSTraverse

算法效率分析
如果使用邻接矩阵,则BFS对于每一个被访问到的顶点,都要循环检测矩阵中的整整一行( n 个元素),总的时间代价为O(n2)。
用邻接表来表示图,虽然有 2e 个表结点,但只需扫描 e 个结点即可完成遍历,加上访问 n个头结点的时间,时间复杂度为O(n+e)。

图的应用

1、最小生成树

**生成树:**所有顶点均由边连接在一起,但不存在回路的图
生成树的特点

  1. 含n个顶点n-1条边(反之不成立)
  2. 生成树是图的极小连通子图,去掉一条边则非连通
  3. 在生成树中再加一条边必然形成回路
  4. 生成树中任意两个顶点间的路径是唯一的

生成树的构造

  1. 在对图进行遍历时,由所有顶点和遍历时经过的边组成的子图即为生成树
  2. 深度优先生成树
  3. 广度优先生成树
  4. 无向图每个连通分量对应一个生成树,形成生成森林
    在这里插入图片描述
    最小生成树
    **概念:**给定一个无向网络,在该网的所有生成树中,使得各边权值之和最小的那颗生成树称为该网的最小生成树,也叫最小代价生成树。
    构造最小生成树 Minimum Spanning Tree
    构造最小生成树的算法很多,其中多数算法都利用了MST的性质
    MST性质
    假设N=(V,E)是一个连通网,U是顶点集V的一个非空子集,若(u,v)是一条具有最小权值的边,其中u∊U,v ∊V-U,则必存在一棵包含边(u,v)的最小生成树

应用案例

  • 图中 n 个顶点分属两个集合:
  • 已落在生成树上的顶点集 U
  • 尚未落在生成树上的顶点集V-U
    则应在所有连通U中顶点和V-U中顶点的边中选取权值最小的边
    在这里插入图片描述

如何求网的最小生成树

  1. 普里姆算法(Prim)
  2. 克鲁斯卡尔算法(Kruskal)

1、普里姆算法(Prim)

  1. 设连通网络 N = { V, E }
  2. 从某顶点 u0 出发,选择与它关联的具有最小权值的边(u0,v),将其顶点加入到生成树的顶点集合U中,将边(u0, v)加入TE中
  3. 每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u, v),把它的顶点加入到U中,将边(u, v)加入TE中
  4. 直到所有顶点都加入到生成树顶点集合U中为止,此时TE有n-1条边,T=(V,TE)是N的最小生成树

总结:m每次从V-U中找一个点sh该点到已确定的顶点U的

在这里插入图片描述
克鲁斯卡尔算法

  1. 设连通网络 N = { V, E }
  2. 构造一个只有 n个顶点,没有边的非连通图 T = { V, ∅ }, 每个顶点自成一个连通分量 在 E
    中选最小权值的边,若该边的两个顶点落在不同的连通分量上(不能形成环),则加入 T 中;否则舍去,重新选择
  3. 重复下去,直到所有顶点在同一连通分量上为止。

在这里插入图片描述
两种算法的比较
在这里插入图片描述

最短路径

1、单源最短路径—用Dijkstra(迪杰斯特拉)算法

  • 初始化:先找出从源点v0到各终点vk的直达路径(v0, vk),即通过一条弧到达的路径。
  • 选择:从这些路径中找出一条长度最短的路径(v0,u) 更新:对其他路径进行适当调整
  • 若在图中存在弧(u,vk),且(v0,u)+(u,vk)<(v0,vk),则以路径(v0,u, vk)代替(v0,vk)
  • 在调整后的各条路径中,再找长度最短的路径,依此类推。
    步骤
    🙇把顶点V分为两组
  • S:已求出最短路径的顶点集合,初始只有源点v0
  • T=V-S:尚未确定最短路径的集合

🙇将T中顶点按最短路径递增的次序加入到S中,保证

  • 从源点v0到S中各顶点的最短路径长度都不大于从v0到T中任何顶点的最短路径长度

每个顶点对应一个距离值:

  • S中顶点:从v0到此顶点的最短路径长度
  • T中顶点:从v0到此顶点的只包括S中顶点作中间顶点的最短路径长度
    在这里插入图片描述

2、所有顶点间的最短路径—用Floyd(弗洛伊德)算法
若<vi,vj>存在,则存在路径{vi,vj} // 路径中不含其它顶点
若<vi,v1>,<v1,vj>存在,则存在路径{vi,v1,vj}
// 路径中所含顶点序号不大于1
若{vi,…,v2}, {v2,…,vj}存在,则存在一条路径{vi, …, v2, …vj}
// 路径中所含顶点序号不大于2
依次类推,则 vi 至 vj 的最短路径应是上述这些路径中,路径长度最小者

步骤
1.初始时设置一个n阶方阵,令其对角线元素为0,若存在弧<vi,vj>,则对应元素为权值,否则为∞
2.逐步试着在元直接路径中增加中间顶点,若加入中间顶点后路径变短,则修改值,否则维持原值。
3.所有顶点试探完毕,算法结束。

在这里插入图片描述
在这里插入图片描述

拓扑排序
有向无环图

有向无环图:无环的有向图,简称DAG图(Directed Acycline Graph)
AOV网: 用一个有向图表示一个工程的各子工程及其相互制约的关系,其中以顶点表示活动,弧表示活动之间的优先制约关系,称这种有向图为顶点表示活动的网,简称AOV网(Activity On Vertex network)
AOE网: 用一个有向图表示一个工程的各子工程及其相互制约的关系,以弧表示活动,一顶点表示活动的开始或结束事件,称这种有向图为边表示活动的网,简称为AOE网(Activity On Edge)
拓扑排序
按照有向图给出的次序关系,将图中顶点排成一个线性序列,对于有向图中没有限定次序关系的顶点,则可以人为加上任意的次序关系。
由此所得顶点的线性序列称之为拓扑有序序列

拓扑排序步骤

  • 输入AOV网络。令 n 为顶点个数。
  • 在AOV网络中选一个没有直接前驱的顶点, 并输出之;
  • 从图中删去该顶点, 同时删去所有它发出的有向边; 重复以上 2、3 步, 直到:
  • 全部顶点均已输出,拓扑有序序列形成,拓扑排序完成;
    图中还有未输出的顶点,但已跳出处理循环。说明图中还剩下一些顶点,它们都有直接前驱,再也找不到没有前驱的顶点了。这时AOV网络中必定存在有向环。

拓扑排序的应用
若以有向图表示一个工程的施工流程图或程序的数据流图,则图中不允许出现回路。
检查有向图中是否存在回路的方法之一,就是对有向图进行拓扑排序。

关键路径

在一个AOE网中,路径长度最长的路径就叫做 关键路径(Critical Path)

路径上各活动持续时间之和叫做路径长度

关键路径的四个描述量

事件的最早发生时间ve(j):从起点到本结点的最长的路径。意味着事件最早能够发生的时刻。
事件的最迟发生时间vl (j):不影响工程的如期完工,本结点事件必须发生的时刻。
活动的最早开始时间:e(ai ) = ve( j )
活动的最迟开始时间: l (ai ) = vl( k ) - dut( j , k )

若l[k] == e[k] 表示活动ai是关键活动。

怎样计算描述量

关键路径
ve(源点) = 0;
ve(k) = Max{ve(j) + dut(<j, k>)}
vl(汇点) = ve(汇点);
vl(j) = Min{vl(k) – dut(<j, k>)}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实例

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

梦森森

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

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

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

打赏作者

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

抵扣说明:

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

余额充值