数据结构笔记 - 图

图(Graph)

相关代码:https://github.com/xu509/Java-practise/tree/master/src/graph

1、 定义

图是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个V是图G中顶点的集合E是图G中边的集合

    • 顶点(Vertex): 图中的数据元素。
    • 图结构中不允许没有顶点,既是顶点集合V有穷非空。
    • 图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以为空。

1.1 各种图定义

无向边:若顶点Vi到Vj之间的边没有方向,则称这条边为无向边(Edge),用无序偶对(Vi,Vj)来表示。

有向边:若从顶点Vi到Vj的边有方向,则称这条边为有向边,也称为弧(Arc)。用有序偶<Vi,Vj>来表示,Vi称为弧尾(Tail),Vj称为弧头(Head)

简单图:若不存在顶点到其自身的边,且同一条边不重复出现,则称这样的图为简单图。

无向完全图:在无向图中,如果任意两个顶点之间都存在边,则称为该图为无向完全图。

有向完全图:在有向图中,如果任意两个顶点之间都存在方向互为相反的两条弧、则称该图为有向完全图。

稀疏图\稠密图:有很少条边或弧的图称为稀疏图,反之称为稠密图。稀疏和稠密是模糊的概念,都是相对而言的。

权(Weight):有些图的边或弧具有与它相关的数字,这种图的边或弧相关的数叫做权。

网(Network):带权的图通常称为网。

子图(Subgraph):假设有两个图G=(V,{E})和G‘=(V',{E'}),如果V’∈V且E‘∈E,则称G’为G的子图。


1.2 图的顶点与边间关系


邻接点(Adjacent):对于无向图 G = (V,{E}),如果边(v,v‘)∈E,则称顶点 v 和 v’ 互为邻接点,即 v 和 v‘ 相关联。边(v,v')依附 (incident) 于顶点v 和 v‘,或者说(v,v’)与顶点v和v‘相关联。

度(Degree):顶点 v 的度是和 v 相关联的边的数目,记为TD(v)。


对于有向图G=(V,{E}),如果弧< v , v' >∈E,则称顶点 v 邻接到顶点 v’ ,顶点 v‘ 邻接自 顶点 v 。弧 <v,v'>和顶点 v,v' 相关联。以顶点 v 为头的弧的数目称为 v 的入度(InDegree),记为ID (v);以 v 为尾的弧的数目称为 v 的出度 (OutDegree),记为OD (v)。


路径的长度是路径上的边或弧的数目。


回路,环(Cycle): 第一个顶点到最后一个顶点相同的路径称为回路或环。

简单路径:序列中顶点不重复出现的路径称为简单路径。

简单回路,简单环:除了第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路,称为简单回路或简单环。


1.3  连通图相关术语


连通图(Connected Graph): 在无向图 G 中,如果从顶点 v 到顶点 v’ 有路径,则称 v 和 v‘是连通的。如果对于图中任意两个顶点 vi 、vj ∈ V, vi和 vj都是连通的,则称G是连通图。


无向图中的极大连通子图称为连通分量。连通分量的概念强调:

  • 要有子图;
  • 子图要是连通的;
  • 连通子图含有极大顶点数;
  • 具有极大定点数的连通子图包含依附于这些顶点的所有边。

有向图 G 中,如果对于每一对 vi、vj∈V、vi ≠ vj ,从 vi 到 vj 和从 vj 到 vi 都存在路径, 则称G是 强连通图。有向图中的极大强连通子图称做有向图的 强连通分量



2、图的抽象数据类型


DATA :顶点的有穷非空集合和边的集合。

OPERATION: CreateGraph、DestroyGraph、LocateVex、GetVex、PutVex、FirstAdjVex(返回邻接顶点)、NextAdjVex(返回下一个邻接顶点)、InsertVex、DeleteVex、InsertArc(增加弧)、DeleteArc、DFSTraverse(深度优先遍历)、HFSTraverse(广度优先遍历)。


3、图的存储结构


由于图的结构比较复杂,不可能用简单的顺序结构来表示。有5种不同的存储结构。


3.1、邻接矩阵Adjacency Matrix

图的邻接矩阵存储方式是用两个数组来表示图。一个一位数组存储图中顶点信息,一个二维数组存储图中的边或弧的信息。


3.2、邻接表Adjacency List

当图中边数相对于顶点较少的图,邻接矩阵的结构对存储空间存在巨大浪费,于是采用数组与链表相结合存储方式,即邻接表。处理方法如下:

  • 顶点表 :图中顶点用一个一位数组存储,每一个数据元素还需要存储指向第一个邻接点的指针。
(留空图片)
  • 边 表:图中每个顶点vi的所有邻接点构成一个线性表,使用单链表存储。
(留空图片)

若图是有向图,即以顶点为弧尾来来存储边表,可容易得到每个顶点的出度。
也有时为了便于确定顶点的入度或以顶点为弧头的弧,则建立一个 逆邻接表,即对每个顶点Vi都建立一个链接为Vi为弧头的表

3.3、 十字链表Orthogonal List

邻接表只关心出度,而逆邻接表只关心入度,而十字链表可结合两者。

  • 顶点表 :图中顶点用一个一位数组存储,数组元素分别为 data  ,firstin,firstout
(留空图片)
firstin 表示入边表头指针, firstout表示出边表头指针。

  • 边    表 :边表结点结构包括,tailvex、headvex、headlink、taillink。如果是网需记录权值。
(留空图片)
tailvex是指弧起点在顶点表的下标。 headvex是指弧终点在顶点表中的下表。
headlink是指入边表指针域,指向终点相同的下一条边。taillink是指出边表指针域,指向起点相同的下一条边。

3.4、邻接多重表

对于无向图的邻接表,如果注重的操作,如删除添加,则需要到这条边的2个边表结点进行操作,步骤则会很繁琐。

因此,仿照十字链表的方式,对边表结点的结构进行改造,能避免上述问题。

  • 边    表 :边表结点结构包括,ivex、ilink、jvex、jlink
(留空图片)
ivexjvex表示某条边依附的两个顶点在顶点表中的下标。
ilink 指向依附顶点 ivex的下一条边。 jlink指向依附于 jvex的下一条边。
注意,ilink指向的结点的jvex一定要和它本身的ivex的值相同。
目前不了解jlink的指向有什么讲究。

3.4、边集数组

对于有向图,边集数组由两个一位数组构成。一个存储顶点的信息;另一个是存储边的信息,这个边数组的数据元素的组成为:起点下标begin、终点下标end、和weight。


4、图的遍历


从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次,这一过程叫做图的遍历(Traversing Graph)


4.1、深度优先遍历DepthFirstSearch

它从图中某个顶点V出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直到所有和v有路径相同的顶点都被访问到为止。


4.2、广度优先遍历BreadthFirstSearch

图的广度优先遍历就类似于树的层序遍历了。


5、最小生成树(Minimum Cost Spanning Tree)

//以下算法代码,均在github中,配合代码才能理解。


我们把构造连通网的最小代价生成树称为最小生成树,找连通图中的最小生成树,经典的有两种算法,普利姆算法克鲁斯卡尔算法


5.1、普利姆(Prim)算法

假设N=(P,{E})是连通网,TE是N上最小生成树中边的集合。算法从U={u0}(u0∈V),TE={}。

重复执行下述操作: 在所有u∈U,v∈V-U的边(u,v)∈E中找到一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直至U=V为止。此时TE中必有n-1条边,则T=(V,{TE})为N的最小生成树。


个人理解:定义2个数组,E[]存储最小生成树的路径集合数组,F[]数组存储到每一个顶点的权。先从一个顶点A开始,遍历他所有的邻接边,将最小的邻接边放入E数组,将其他所有邻接边放入F数组,再获取最小邻接边所衔接的邻接点B,将B中所有邻接边的权遍历,将小于F数组中相应权的数值更新进F[](其中不包括已经存入E数组的路径),然后在F中取得最小路径放入E,由此循环。


5.2、克鲁斯卡尔Kruskal)算法

假设N=(V,{E})是连通网,则令最小生成树的初始状态为只有n个顶点而无边的非连通图 T = {V,{}}.图中每个顶点自成一个连通分量。在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。以此类推,直至T中所有顶点都在同一连通分量上为止。


个人理解:图数据以边集数组形式保存,排序出权值最小的边,加入图中。然后依次加入除初始边外其他最小的边,如果在新图中形成环则舍弃,否则添加,直到所有顶点都成1连通分量停止。



6、最短路径


6.1、迪杰斯特拉(Dijkstra)算法

和prim算法的想法一样,逐个获取路径,如先获取V0 -V1的路径,然后在此基础上获取V0-V2的路径。


6.2、佛洛依德(Floyd)算法

个人理解:图的数据结构由邻接矩阵组成。重点思想:设 a为路径起点,b为路径重点,k为中转顶点。如果a -> b 的权值 > a->k + k->b,即经过中转顶点后,a至b的权值小于a和b的直接路径,则修改邻接矩阵的权值,由含中转顶点的权值代入。

具体实现需看代码理解。


7、拓扑排序

 

7.1 拓扑排序介绍

AOV网: 在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称为AOV网(Activity on Vertex Network)。

拓扑序列: 设G={V,E}是一个具有n个顶点的有向图,V中的顶点序列V1,V2.....Vn,满足若从顶点Vi到Vj有一条路径,则在顶点序列中顶点Vi必在顶点Vj之前。则我们称这样的顶点序列为一个拓扑序列。

拓扑排序:是对一个有向图构造拓扑序列的过程。


7.2 拓扑排序算法

基本思路:从AOV网中选择一个入度为0的顶点输出,然后删去此顶点,并删除以此顶点为尾的弧,重复此步骤,直到全部顶点或AOV网中不存在入度为0的顶点为止。

写的例子思路:   1、先遍历顶点数组,将入度为0的顶点压入堆栈。

2、出栈1个入度为0的顶点,并获取他的边结点链表。

3、获取边结点链表,如果边结点链表,将链表中所有顶点入度减去1。

4、如果对应顶点为0,再次压入堆栈,重新回到2。

5、等所有栈中元素都出栈后,如果循环次数小于顶点数,则说明有环,该图非AOV网。


8、关键路径


8.1 概念

在一个表示工程的带权有向图中,用顶点表示事件,用有向边表示活动,用边上的权值表示活动的持续时间,这种有向图的边表示活动的网,我们称之为AOE网(Activity On Edge Network)。


我们把路径上各个活动所持续的时间之和称为路径长度,从源点到汇点具有最大长度的路径叫关键路径,在关键路径上的活动叫关键活动


8.2 关键路径算法原理 

这里举个例子,一学生放学回家后离睡觉有4小时的空闲时间,而家庭作业需要2小时完成。如果一回家就做家庭作业即是该活动的最早开始时间,可以理解成0,如果拖延2小时后再做家庭作业,则这个时间为活动的最晚开始时间,这里理解成2。如果需要做4小时的作业,即回家后直到睡觉都需要做作业,那最早开始时间等于最晚开始时间,则把做作业这个活动称为关键活动

-事件的最早发生时间etv(earliest time of vertex):即顶点Vk的最早发生时间。

-事件的最晚发生时间ltv(latest time of vertex):即顶点Vk的最晚发生时间。

-活动的最早开工时间ete(earliest time of edge):即弧Ak的最早发生时间。

-活动最晚开工时间lte(latest time of edge):即弧Ak的最晚发生时间。

可通过etv和ltv获得ete和lte,然后再根据etep[k]和lte[k]来判断Ak是否为关键活动。

etv[k] = 0 , 当k = 0时,

etv[k] = max{etv[i] + len<Vi,Vk>}  当k≠0且<Vi,Vk>∈P[k]时,

len表示弧<Vi,Vk>的权值


ltv[k] = etv[k] , 当k = n - 1

ltv[k] = min{ltv[j] - len<Vk,Vj>} ,当k<n-1且<Vk,Vj>∈S[k]时

S[K]表示所有从顶点出发的弧的集合。



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值