图(Graph)是一种较线性表和树更为复杂的数据结构。


基本概念

有向图:由顶点集和弧集构成的图称为有向图。

无向图:由顶点集和边集构成的图称为无向图。

有向网或无向网:有向图或无向图中的弧或边带权后的图分别称为有向网或无向网。

完全图:图中有n个顶点,n(n-1)/2条边的无向图称为完全图。

有向完全图:图中有n个顶点,n(n-1)条弧的有向图称为有向完全图。

稀疏图:假设图中有n个顶点e条边(或弧),若边(或弧)的个数e<nlogn,则称为稀疏图。否则称为稠密图。

邻接点:若无向图中顶点v和w之间存在一条边(v,w),则称顶点v和w互为邻接点,称边(v,w)依附于顶点v和w或边(v,w)与顶点v和w相关联。

顶点的度:在无向图中的顶点v关联的边的数组定义为v的度,记作TD(v)。

简单路径:顶点不重复的路径称为简单路径。

回路:首尾顶点相同的路径称为回路。

简单回路:除了首尾顶点,中间任何一个顶点都不重复的回路称为简单回路。

连通图:在无向图中,若顶点Vi到Vj有路径存在,则称Vi和Vj是连通的。若无向图中任意两个顶点之间都有路径想通,既是连通的,则称此图为连通图;否则,称其为非连通图。无向图中各个极大连通子图称为该连通的连通分量。

强连通图:在有向图中,若任意两个顶点之间都存在一条有向路径,则称此有向图为强连通图。否则,称其为非强连通图。有向图中各个极大强连接子图称为该图的强连通分量。

生成树:包含连接图中全部顶点的极小连通子图称为该树的生成树,即假设一个连通图有n个顶点和e条边,其中n个顶点和n-1条边构成一个极小连通图,该极小连通子图为此连通图的生成树。对非连通图,由各个连通分量的生成树构成的集合称为该非连通图的生成树。


图的存储

邻接矩阵:图的邻接矩阵是表示顶点之间相邻关系的矩阵,是顺序结构,故也称为数组表示法。

特点:1、存储空间,由于无向图的邻接矩阵是对称矩阵,采用特殊矩阵的压缩存储,即下三角矩阵即可完成。因为,具有n个顶点的无向图,只需要n(n-1)/2个空间即可。但是,对于有向图而言,邻接矩阵不一定是对称的,所以仍然需要n^2个空间。2、运算,采用邻接矩阵可以方便的判定图或网中顶点与顶点之间是否有关联,即根据矩阵中元素的值可直接判定。另外,对于求解各个顶点的度也是非常方便的。

邻接表:当图中的边(或弧)数远远小于图中的顶点树时,即为稀疏图时,邻接矩阵就成为稀疏矩阵,此时用邻接矩阵存储图就会造成空间浪费。一个较好的解决方法就是采用邻接表。

特点:1、存储空间,对于有n个顶点e条边的无向图,采用邻接表存储,需要n个表头结点和2e个表结点。显然,在稀疏矩阵中,用邻接表比邻接矩阵的存储空间要节省。2、运算,对于无向图,TD(Vi)=第i个单链表上结点的个数,对于有向图(网),OD(Vi)=第i个单链表上结点的个数,但是要求第i个结点的入度ID,必须遍历整个邻接表,统计该结点出现的次数。显然,这种操作耗费时间较大。为了方便这类操作,可以为图建立一个逆邻接表。逆邻接表的结构与邻接表完全相同,只是边表的每个结点存放的是该顶点通过入度弧所邻接的所有顶点。

十字链表

多重链表


图的遍历

深度优先搜索遍历(Depth-First Search,DFS):深度优先搜索遍历是类似树的先序遍历。尽可能先对纵深方向进行搜索。基本思想为从图中某个顶点V0出发,访问此顶点,然后依次从V0的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和V0有路径相同的顶点都被访问到,若是连通图,则遍历过程结束;否则,图中还有顶点未被访问,则另选图中一个未被访问的顶点作为新的出发点,重复上述过程,直至图中所有顶点都被访问到。

广度优先搜索遍历(Breadth-First Search,BFS):图的广度优先搜索遍历类似于树的按层次遍历。基本思想为从图中的某个顶点V0出发,在访问此顶点之后一次访问V0的所有未被访问的邻接点,之后按照这些邻接点被访问的先后次序依次访问它们的邻接点,直至图中所有和V0有路径相通的顶点都被访问到。若此图中尚有顶点未被访问到,则另选图中一个未被访问的顶点作为新的出发点,重复上述过程,直至图中所有顶点都被访问到。

*可以利用图的遍历搜索过程来判断一个图是否连通,如果在遍历的过程中,不止一次调用搜索过程,则说明该图是一个非连接图,而且调用几次遍历过程,说明该图有几个连通分量。


最小(代价)生成树

Prim算法(也称加点法)

基本思想:从连接网络N={v,E}中的某一顶点u0出发,选择与他关联的具有最小权值的边(u0,v),将其顶点加入到最小生成树的顶点集合U中。以后每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u,v),把它的顶点加入到集点V中,这意味着(u,v)也加入到生成树的边集合中。如此下去,直到网络中的所有顶点都加入到生成树顶点集合U中为止。

Kruskal算法(也称加边法)

基本思想:先构造一个含有n个顶点的子图SG,然后从权值最小的边开始,若它的添加不是SG中产生回路,则在SG上加上该边,依次按照权值递增的次序,选择合适的边进行添加,如此重复,直至加完n-1条边为止。


拓扑排序

I、从有向图中选取一个没有前驱的顶点并输出之。

II、从有向图中删去该顶点以及所有以它为尾的弧。

重复上述两步,直至图空(不存在回路),或者图不空但找不到无前驱的顶点为止(存在回路)。可见,拓扑排序可以检测有向图中是否存在回路。由于可能同时存在多个没有前驱的顶点,因而拓扑序列是不唯一的,但是一旦存储结构及算法确定,拓扑序列就是唯一确定的。

具体实现:采用邻接表作为存储结构,将寻找没有前驱结点的顶点转化为寻找入度为0的顶点,删除以该顶点为弧尾的顶点转化为将该顶点的入度减1.由此,可看出整个算法的关键始终和顶点的入度值相关联。因而,必须时刻记录每个顶点当前的入度值,为此,设置一个辅助数组indegree[]用来记录每个顶点的入度值。该数组元素值都为0,通过扫描邻接表的各条链,遇到顶点Vi,便将对应的indegree[i]值加1,最终获得该图中每个顶点的入度值。


关键路径

网中仅有一个入度为0的顶点为源点,表示工程开始;也仅有一个出度为0的顶点称为汇点,表示工程的结束。

从源点到汇点之间可能有很多条路径。这些路径中具有最长路径长度的路径被称为关键路径

ve(j)--事件(顶点)的最早发生时间:从源点到顶点j的最长路径。ve(0)=0。

vl(i)--事件(顶点)的最迟发生时间:从顶点i到汇点的最短路径长度。vl(n)=ve(n)。


最短路径

单源最短路径问题(Dijkstra算法)

算法思想

I、初始时,集合S中仅包含源点V0,集合V-S中包含除源点v0以外的所有顶点,v0到V-S中各顶点的路径长度或者为某个权值(如果它们之间有弧相连),或者为正无穷(没有弧相连)。

II、按照最短路径长度递增的次序,从集合V-S中选出到顶点v0路径长度最短的顶点vk加入到集合S中。

III、加入vk之后,为了寻找下一个最短路径,必须修改从v0到集合V-S中剩余所有顶点vi的最短路径。若在路径上加入vk之后,使得v0到vi的路径长度比原来没有加入vk时的路径长度短,则修正v0到vi的路径长度为其中短的。

IV、重复以上步骤,直至集合V-S中的顶点全部加入到集合S中为止。

每对顶点之间的最短路径问题(Floyd算法)

由已经介绍的Dijkstra算法也可以解决每对顶点之间的最短路径问题,只需要每次以一个顶点作为源点,重复调用Dijkstra算法n次即可。显然,这样执行下来的时间复杂度将达到O(n^3)。解决这个问题还有一个比较直接的算法——Floyd算法。这个算法属于典型的动态规划算法,先自底向上分别求解子问题的解,然后由这些子问题的解得到原问题的解。虽然这个算法的时间复杂度也达到了O(n^3),但是形式相对简单一些。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值