Graph
一种由顶点 (Vertex) 和边 (Edge) 组成的非线性数据结构

一、基础知识

我们可以将图 G 抽象地表示为一组顶点 V 和一组边 E 的集合:如果将顶点看作节点,将边看作连接各个节点的引用(指针),我们就可以将图看作一种从链表拓展而来的数据结构。

相较于线性关系(链表)和分治关系(树),网络关系(图)的自由度更高,因而更为复杂。

Pasted image 20250706232826.png

常用术语

邻接(adjacency):当两顶点之间存在边相连时,称这两顶点“邻接”
路径(path):从顶点 A 到顶点 B 经过的边构成的序列被称为从 A 到 B 的“路径”
度(degree):一个顶点拥有的边数。对于有向图,入度(in-degree)表示有多少条边指向该顶点,出度(out-degree)表示有多少条边从该顶点指出。

二、图的常见类型

Pasted image 20250706232924.png

1. 所有顶点是否连通

可分为连通图(connected graph)和非连通图(disconnected graph):

2. 边是否具有方向

可分为无向图(undirected graph)和有向图(directed graph):

3. 边是否具有权重

可分为无权图 (unweighted graph) 有权图 (weighted graph):

三、图的数学表示

对于一个含有 n 个顶点的图 G=(V,E)

Pasted image 20250706235230.png

1. 邻接矩阵 Adjacency Matrix

设图的顶点数量为 n,邻接矩阵使用一个 n×n 大小的矩阵来表示图,每一行(列)代表一个顶点,矩阵元素代表边,用 1 或 0 表示两个顶点之间是否存在边。

A[i][j]={1if(i,j)E0else

邻接矩阵具有以下特性:

使用邻接矩阵表示图时,我们可以直接访问矩阵元素以获取边,因此增删查改操作的效率很高,时间复杂度均为 O(1) 。然而,矩阵的空间复杂度为 O(n2),内存占用较多。

2. 邻接表 Adjacency List

邻接表使用n链表来表示图,链表节点表示顶点。第 𝑖 个链表对应顶点 𝑖 ,其中存储了该顶点的所有邻接顶点(与该顶点相连的顶点)。

邻接表仅存储实际存在的边,而边的总数通常远小于 n2,因此它更加节省空间。然而,在邻接表中需要通过遍历链表来查找边,因此其时间效率不如邻接矩阵。

A —— B —— C  

A: B  
B: A, C  
C: B  
# 无向图
graph = {
    'A': ['B'],
    'B': ['A', 'C'],
    'C': ['B']
}

# 加权图扩展
graph = {
    'A': [('B', 2)],
    'B': [('A', 2), ('C', 3)],
    'C': [('B', 3)]
}

邻接表结构与哈希表中的“链式地址”非常相似,因此我们也可以采用类似的方法来优化效率。

四、图的基础操作

主要分为:对“边”的操作和对“顶点”的操作

1. 基于邻接矩阵的实现

以空间换时间

2. 基于邻接表的实现

以时间换空间

3. 图的遍历

图的遍历