有向图的通用性更强,因为无向图和混合图都可以转化为有向图
n个顶点无向图最多n(n-1)/2 条边
n个顶点有向图n(n-1) 条边
G=(V,E) vertex edge
E=(u,v)
图算法的时间空间性能,都与图结构的具体实现方式紧密相关,假定图的顶点个数为n,边数为e
邻接矩阵:是图ADT最基本的实现方式,使用方阵A[n][n]表示由n个顶点构成的图,其中每个单元负责描述一对顶点之间可能存在的邻接关系,所以叫邻接矩阵。(可使用二维vector<vector<int>>
类型存储边,vector<int>
类型存储顶点)
顶点和边的静态查询操作:o(1)的时间
动态操作比较耗时,加上向量扩容的代价,分摊时间复杂度为o(n)
空间:o(n*n)
无向图的邻接矩阵必为对称阵。
邻接表:只需将邻接矩阵中的边关系逐行的转换为链表存储(只记录存在的边),得到一些列表,就叫做邻接表。
空间:o(n+e)
静态操作:查找o(n),
动态操作:顶点插入o(1),顶点删除o(n)
邻接表对于枚举同一顶点的所有关联边很方便,所以以下对于图的各种算法复杂度分析都是基于邻接表的实现方式。
图的遍历:
时间复杂度:o(n+e)
广度优先搜索(BFS):越早被访问到的顶点,其邻居越是优先被选用
类似于树的层次遍历
借助一个队列来保存已被发现,但是尚未访问完毕的顶点,每一次取出队首顶点,逐一访问其邻居并处理,然后将该顶点置为visited状态,从队首取出下个顶点,进入下一次迭代。
BFS遍历输出的顺序就是BFS树。
空间复杂度:o(n+e)
时间复杂度:o(n+e)
应用:基于BFS可解决连通域分解,最短路径等问题
深度优先搜索(DFS):优先选取最后一个被访问到的顶点的邻居。
访问次序的输出结果类似于树的后序遍历
空间复杂度:o(n+e)
时间复杂度:o(n+e)
应用:连通域分解,有向无环图(DAG)的判定
dfs应用1:
拓扑排序:将图的所有顶点排成一个线性序列,每一个顶点都不会通过边,指向其在此序列中的前驱顶点。有向无环图的拓扑排序必然存在,因为任一有向无环图必包含入度为0的顶点,否则就会包含环路,所以只要将入度为0的点取出,剩下的图依然是有向无环图,也必然存在拓扑排序。
同理,也必然存在出度为0的顶点,在DFS遍历中,首先因为访问完成而转化为visited状态的顶点m,必然具有出度为0的性质。所以,DFS遍历过程中,各顶点被标记为visited的次序,恰好按逆序给出了原图的一个拓扑排序,所以可以在DFS遍历中增加一个栈,一旦有被标记为visited的顶点,就入栈,所有顶点访问完毕后,依次出栈就是拓扑排列。
由于多个入度出度为0的顶点存在,导致拓扑排序的结果不唯一,结果取决于每次DFS起点的选择决定
时间空间复杂度都是o(n+e)
因为非DAG/有向无环图 无法拓扑排序,dfs搜索中一旦发现后向边(也就是遍历到了discovered状态的顶点),就可以判定该图是DAG(dfs搜索善于检测环路特性)
双连通域分解(对于无向图):
任一无向图都可视作由若干个极大的双连通子图组合而成,这样的每一个子图都称作原图的一个双连通域
关节点:删除关节点后,图所包含的连通域增多
关节点很重要,网络系统中对应网关,决定子网之间能否连通,所以我们往往需要找出关节点,并给予重点保护。找关节点的方法:
1、根据定义暴力算法,对每个顶点,删除后看看连通域数目是否增多(dfs或bfs统计连通域数目)
时间复杂度:o(n(n+e))
2、基于DFS
在DFS搜索的过程中记录并更新各顶点V所能(经过后向边)连通的最高祖先,即可及时确认关节点,并报告对应的双连通域。
空间复杂度:o(n+e)
时间复杂度:o(n+e)
//
优先级搜索(PFS):无论是dfs还是bfs,都是选取当前策略下优先级最高的顶点,以迭代方式,逐步引入顶点和边,最终构造出一颗遍历树。
1、最小支撑树:
支撑树:
针对保留的原图中的边的数目而言,支撑树既是“禁止环路”前提下的极大子图,也是“保持连通”前提下的最小子图。支撑树不唯一,但是顶点总数都是n,保留的边数都是n-1
最小支撑树:
若图G为一组带权网络,则每一颗支撑树的成本就是所采用各边的权重的总和,成本最小的就称为最小支撑树。
应用:
聚类分析,网络架构设计,VLSI布线设计,都可以转化为最小支撑树的构造问题,另外,最小支撑树构造算法也可以作为一些NP问题提供足够快速,足够近似的解法。
算法:
采用PFS搜索框架,使用适当的顶点优先级更新策略,即可得出高效的最小支撑树构造算法。
prim算法:最小支撑树总是会采用连接每一割的最短跨边。采用贪心迭代策略,从一个顶点出发,每次找一个割的最短跨边。
时间复杂度:o(n^2),其效率可以借助优先级队列进一步提高
2、最短路径:对于带权图,我们常关心一类问题:给定带权网络,以及源点s,对于所有其他的顶点v,s到v的最短通路有多长?该通路由哪些边构成?
最短路径树:单调性,歧义性,无环性
Dijkstra算法:时间复杂度o(n^2),其效率可以借助优先级队列进一步提高