图的基本概念
图的定义
图是由顶点和连接顶点的边组成的数据结构。顶点也称结点或交点,边也称链接。
图的种类
根据图中的边是否有方向以及是否有权重,可以将图分成无向图和有向图,以及无权图和带权图。
无向图中的每条边没有方向,每条边在两个方向上连通;有向图中的每条边有方向,每条边只在一个方向上连通。
无权图中的每条边没有权重,每条边的权重相同;带权图中的每条边有权重,权重表示边的特定信息,例如长度或开销。
由于每个图一定是无向图和有向图之一,以及无权图和带权图之一,因此按照是否有方向以及是否有权重,可以将图分成四类:无向无权图、无向带权图、有向无权图、有向带权图。
图的术语
根据图中的顶点和顶点之间的关系以及边和顶点之间的关系,定义术语邻接和关联。
在无向图中,如果有一条边连接顶点 u u u 和顶点 v v v,则顶点 v v v 和顶点 u u u 邻接且顶点 u u u 和顶点 v v v 邻接。在有向图中,如果有一条边从顶点 u u u 指向顶点 v v v,则顶点 v v v 和顶点 u u u 邻接。连接顶点 u u u 和顶点 v v v 的边与顶点 u u u 和顶点 v v v 关联。
根据关联的定义,可以定义无向图中顶点的度以及有向图中顶点的出度和入度。
在无向图中,一个顶点的度为与该顶点关联的边数。在有向图中,一个顶点的出度为与该顶点关联且以该顶点为起点的边数,一个顶点的入度为与该顶点关联且以该顶点为终点的边数。
图的表示方法
邻接链表和邻接矩阵
图的两种标准表示方法是邻接链表和邻接矩阵,都可以表示无向图和有向图以及无权图和带权图。
在无权图中,每条边的权重相同,只需要考虑顶点之间的邻接关系。
邻接链表表示为一个长度等于顶点数的链表数组。每个顶点对应一个链表,顶点 v v v 对应的链表包含所有和顶点 v v v 邻接的顶点。
邻接矩阵表示为一个行数和列数都等于顶点数的矩阵。矩阵的第 i i i 行第 j j j 列的元素表示顶点 j j j 是否和顶点 i i i 邻接,如果元素值为 1 1 1 则顶点 j j j 和顶点 i i i 邻接,如果元素值为 0 0 0 则顶点 j j j 和顶点 i i i 不邻接。对于无向图,邻接矩阵是对称矩阵。
考虑以下无向图。
其邻接链表和邻接矩阵的表示分别如下。
0 : [ 1 , 2 , 3 ] 1 : [ 0 , 2 ] 2 : [ 0 , 1 , 3 ] 3 : [ 0 , 2 ] \begin{aligned} 0 &: [1, 2, 3] \\ 1 &: [0, 2] \\ 2 &: [0, 1, 3] \\ 3 &: [0, 2] \\ \end{aligned} 0123:[1,2,3]:[0,2]:[0,1,3]:[0,2]
0 1 1 1 1 0 1 0 1 1 0 1 1 0 1 0 \begin{matrix} 0 & 1 & 1 & 1 \\ 1 & 0 & 1 & 0 \\ 1 & 1 & 0 & 1 \\ 1 & 0 & 1 & 0 \end{matrix} 0111101011011010
考虑以下有向图。
其邻接链表和邻接矩阵的表示分别如下。
0 : [ 1 , 2 ] 1 : [ 2 ] 2 : [ 3 ] 3 : [ 0 ] \begin{aligned} 0 &: [1, 2] \\ 1 &: [2] \\ 2 &: [3] \\ 3 &: [0] \\ \end{aligned} 0123:[1,2]:[2]:[3]:[0]
0 1 1 0 0 0 1 0 0 0 0 1 1 0 0 0 \begin{matrix} 0 & 1 & 1 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 \end{matrix} 0001100011000010
对于带权图,邻接链表中的每个元素增加一个边的权重信息,邻接矩阵中的每个元素存储权重信息,即可表示带权图。使用邻接矩阵表示带权图时,不存在的边可以使用 0 0 0 或 ∞ \infty ∞ 表示。
用 V V V 和 E E E 分别表示图中的顶点集合和边集合,邻接链表和邻接矩阵的对比如下。
-
邻接链表的空间复杂度是 O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|) O(∣V∣+∣E∣),邻接矩阵的空间复杂度是 O ( ∣ V ∣ 2 ) O(|V|^2) O(∣V∣2)。当图中的边数较少时,邻接链表的空间复杂度较低,因此邻接链表是更好的表示方法;当图中的边数较多时,邻接矩阵的空间复杂度不会显著高于邻接链表,因此邻接矩阵使用较多。
-
由于邻接链表的空间复杂度较低,只存储和每个顶点邻接的顶点,因此邻接链表可以直接得到和一个特定顶点邻接的顶点集合,而邻接矩阵需要遍历所有顶点才能得到和一个特定顶点邻接的顶点集合。
-
邻接矩阵可以使用 O ( 1 ) O(1) O(1) 的时间得到两个顶点是否邻接,而邻接链表需要使用 O ( ∣ V ∣ ) O(|V|) O(∣V∣) 的时间得到两个顶点是否相邻。
其他表示方法
除了两种标准表示方法以外,还有其他的方法可以表示图。
LeetCode 中有两种常见的表示图的方法,分别是邻接顶点数组和边数组。
-
邻接顶点数组表示为一个长度等于顶点数的数组,数组中的每个元素是一个数组,表示与当前顶点邻接的顶点。
-
边数组表示为一个长度等于边数的数组,数组中的每个元素是一个数组,表示无向图中的一条边关联的两个顶点或者有向图中的一条边的起点和终点。
邻接顶点数组和边数组的表示方法都可以用于表示无向图和有向图,对于带权图可以通过增加权重信息的方式表示。