图论算法(3):图的基本表示(邻接矩阵、邻接表、邻接矩阵与邻接表的对比)

本章节内容使用 java 实现,Github 代码仓:https://github.com/ZhekaiLi/Code/tree/main/Graph/src

查看文章内的图片可能需要科学上网! 因为使用了github管理图片,因此如果出现无法加载的情况请翻墙

【参考资料】imooc 波波老师:玩转算法系列–图论精讲 面试升职必备(Java版)

【往期博客链接】
图论算法(1、2):图的分类、图的基本概念(无向图与有向图、无权图、无环图、完全图、二分图;简单图、连通分量、图的生成树、子图与母图)
图论算法(3):图的基本表示(邻接矩阵、邻接表、邻接矩阵与邻接表的对比)
图论算法(4):图的深度优先遍历 DFS
图论算法(5):图的广度优先遍历 BFS
图论算法(6):LeetCode 图论算法练习(785.判断二分图、695.岛屿的最大面积、Floodfill 算法、并查集)

3. 图的基本表示

3.1 邻接矩阵

G = ( V , E ) G = (V, E) G=(V,E)邻接矩阵(adjacency matrix) C C C 是如下定义的:
C = ( c i j ) n × n ∈ { 0 , 1 } n × n c i j = { 1 ,      ( i , j ) ∈ E 0 ,      ( i , j ) ∉ E \begin{aligned} C&=(c_{ij})_{n\times n}\in\{0,1\}^{n\times n}\\ c_{ij}&=\begin{cases} 1,\;\;(i,j)\in E\\ 0,\;\;(i,j)\notin E \end{cases} \end{aligned} Ccij=(cij)n×n{ 0,1}n×n={ 1,(i,j)E0,(i,j)/E


示例:有向图及其邻接矩阵

而对于无向图来说,其邻接矩阵是对称的( c i j = c j i c_{ij}=c_{ji} cij=cji

可以用下图中央这样的两列数据来表示一个无向图,然后将其翻译为邻接矩阵



java 实现:AdjMatrix.java

3.2 邻接表

为什么要引入邻接表?(邻接矩阵的复杂度)



邻接矩阵的的建图时间复杂度 O ( E ) O(E) O(E)(遍历每条边),以及判断两点是否相邻的时间复杂度 O ( 1 ) O(1) O(1) 没有提升空间,但其空间复杂度以及求相邻节点的时间复杂度较大

尤其是例如对于一个有3000个节点的树(无向图),它只有2999条边,即使是乘2也只有6000不到组数据,但是其对应的邻接矩阵的空间复杂度却是 O ( 300 0 2 ) O(3000^2) O(30002)近千倍的差距!

邻接表的定义

图的邻接表(adjacency list) 是所有节点的邻接表的集合
各节点的邻接表由其:

  1. 邻边(无向图)
  2. 出弧(有向图)

组成,并用一个单向链表列出,链表中每个单元对应于一条邻边/出弧,此外还可以包含弧上的权等作为数据域。

邻接表的表示

对于有向图 G = ( V , E ) G = (V, E) G=(V,E),一般用 A ( i ) A(i) A(i) 表示节点 i i i 的邻接表,即节点 i i i 的所有出弧构成的集合或链表

对于无向图 A ( i ) A(i) A(i) 则表示节点 i i i 邻边的集合

图的整个邻接表还可以用一个指针数组表示。例如:(下图中第一个指针数组表示, 1 → 2 1\to2 12 的权重为8, 1 → 3 1\to3 13 的权重为9)



java 实现:AdjList.java

邻接表的复杂度



相较于邻接矩阵的复杂度,邻接表在空间复杂度、求相邻节点的时间复杂度这两方面有明显优势,但其建图的时间复杂度、判断两点是否相邻的时间复杂度较大

降低这两个复杂度的关键在于实现快速查看重复边/ 快速判断两点是否相邻,因此我们可以使用哈希表 O ( 1 ) O(1) O(1) 或红黑树 O ( log ⁡ V ) O(\log V) O(logV) 代替链表(在 java 中分别对应 HashSet, TreeSet, LinkedList)

java 实现:Graph.java(使用红黑树)

3.3 比较:矩阵 vs 两种表



因此我门最终选用邻接表(TreeSet) 作为图的表达形式(当然也可以使用HashSet)

猜你喜欢

转载自blog.csdn.net/weixin_43728138/article/details/118937568