《图算法与计算机网络》系列 · 第 1 篇
本文是系列的开篇之作,将带你理解为什么计算机网络本质上是图结构,以及图算法如何在网络中发挥关键作用。
系列文章导航
| 篇目 | 标题 |
|---|---|
| 第 1 篇 | 计算机网络与图算法:从理论到实践 |
| [第 2 篇](#篇目 标题 第 1 篇 计算机网络与图算法:从理论到实践 第 2 篇 从 Dijkstra 到 A*:贪心策略与启发式搜索 第 3 篇 Bellman-Ford、SPFA 与 Floyd-Warshall:动态规划的力量 第 4 篇 构建最优网络:Prim 与 Kruskal 算法 第 5 篇 探索网络结构:BFS、DFS 与拓扑排序 第 6 篇 流量优化之道:Ford-Fulkerson 最大流算法) | 从 Dijkstra 到 A*:贪心策略与启发式搜索 |
| [第 3 篇](#篇目 标题 第 1 篇 计算机网络与图算法:从理论到实践 第 2 篇 从 Dijkstra 到 A*:贪心策略与启发式搜索 第 3 篇 Bellman-Ford、SPFA 与 Floyd-Warshall:动态规划的力量 第 4 篇 构建最优网络:Prim 与 Kruskal 算法 第 5 篇 探索网络结构:BFS、DFS 与拓扑排序 第 6 篇 流量优化之道:Ford-Fulkerson 最大流算法) | Bellman-Ford、SPFA 与 Floyd-Warshall:动态规划的力量 |
| [第 4 篇](#篇目 标题 第 1 篇 计算机网络与图算法:从理论到实践 第 2 篇 从 Dijkstra 到 A*:贪心策略与启发式搜索 第 3 篇 Bellman-Ford、SPFA 与 Floyd-Warshall:动态规划的力量 第 4 篇 构建最优网络:Prim 与 Kruskal 算法 第 5 篇 探索网络结构:BFS、DFS 与拓扑排序 第 6 篇 流量优化之道:Ford-Fulkerson 最大流算法) | 构建最优网络:Prim 与 Kruskal 算法 |
| [第 5 篇](#篇目 标题 第 1 篇 计算机网络与图算法:从理论到实践 第 2 篇 从 Dijkstra 到 A*:贪心策略与启发式搜索 第 3 篇 Bellman-Ford、SPFA 与 Floyd-Warshall:动态规划的力量 第 4 篇 构建最优网络:Prim 与 Kruskal 算法 第 5 篇 探索网络结构:BFS、DFS 与拓扑排序 第 6 篇 流量优化之道:Ford-Fulkerson 最大流算法) | 探索网络结构:BFS、DFS 与拓扑排序 |
| [第 6 篇](#篇目 标题 第 1 篇 计算机网络与图算法:从理论到实践 第 2 篇 从 Dijkstra 到 A*:贪心策略与启发式搜索 第 3 篇 Bellman-Ford、SPFA 与 Floyd-Warshall:动态规划的力量 第 4 篇 构建最优网络:Prim 与 Kruskal 算法 第 5 篇 探索网络结构:BFS、DFS 与拓扑排序 第 6 篇 流量优化之道:Ford-Fulkerson 最大流算法) | 流量优化之道:Ford-Fulkerson 最大流算法 |
文章目录
-
- 系列文章导航
- [1. 为什么计算机网络是图?](#1. 为什么计算机网络是图?)
-
- [1.1 从现实网络到抽象图](#1.1 从现实网络到抽象图)
- [1.2 实际案例:互联网拓扑](#1.2 实际案例:互联网拓扑)
- [1.3 网络问题 = 图问题](#1.3 网络问题 = 图问题)
- [2. 图的基本概念回顾](#2. 图的基本概念回顾)
-
- [2.1 图的定义](#2.1 图的定义)
- [2.2 图的分类](#2.2 图的分类)
-
- [有向图 vs 无向图](#有向图 vs 无向图)
- [加权图 vs 无权图](#加权图 vs 无权图)
- 环路与连通性
- [3. 图的存储结构](#3. 图的存储结构)
-
- [3.1 邻接矩阵(Adjacency Matrix)](#3.1 邻接矩阵(Adjacency Matrix))
- [3.2 邻接表(Adjacency List)](#3.2 邻接表(Adjacency List))
- [3.3 边列表(Edge List)](#3.3 边列表(Edge List))
- [3.4 存储结构对比](#3.4 存储结构对比)
- [4. 图算法分类概览](#4. 图算法分类概览)
-
- [4.1 最短路径算法](#4.1 最短路径算法)
- [4.2 最小生成树算法](#4.2 最小生成树算法)
- [4.3 图遍历算法](#4.3 图遍历算法)
- [4.4 网络流算法](#4.4 网络流算法)
1. 为什么计算机网络是图?
1.1 从现实网络到抽象图
计算机网络本质上就是一个**图(Graph)**结构。让我们来看看如何对应:
对应关系:
| 网络概念 | 图论概念 | 说明 |
|---|---|---|
| 路由器、交换机 | 节点(Vertex) | 网络设备 |
| 物理链路、逻辑连接 | 边(Edge) | 设备间的连接 |
| 延迟、带宽、成本 | 权重(Weight) | 边的属性 |
1.2 实际案例:互联网拓扑
北京核心节点
/ | \
/ | \
上海 广州 成都
/ | \ / \ / |
南京 杭州...深圳... 重庆 昆明
这就是一个典型的有向加权图:
- 节点:各个城市的网络节点
- 边:城市间的网络链路
- 权重:链路延迟、带宽成本等
1.3 网络问题 = 图问题
| 网络问题 | 图论问题 | 对应算法 |
|---|---|---|
| 最优路由选择 | 最短路径 | Dijkstra、A*、Bellman-Ford、Floyd-Warshall |
| 网络拓扑设计 | 最小生成树 | Prim、Kruskal |
| 网络发现 | 图遍历 | BFS、DFS |
| 带宽优化 | 最大流 | Ford-Fulkerson |
2. 图的基本概念回顾
2.1 图的定义
图(Graph) 由两部分组成:
- 顶点集 V(Vertex):所有节点的集合
- 边集 E(Edge):所有边的集合
python
# 图的 Python 表示
graph = {
'V': {0, 1, 2, 3}, # 顶点集
'E': [(0,1), (0,2), (1,3), (2,3)] # 边集
}
2.2 图的分类
有向图 vs 无向图
无向图:A─────B (边没有方向,可以双向通行)
\ /
\ /
C
有向图:A → B (边有方向,只能单向通行)
↓ ↘
C → D
网络中的应用:
- 无向图:对等网络连接、以太网
- 有向图:客户端 - 服务器模型、单向链路
加权图 vs 无权图
无权图:A───B (只关心是否连通)
│ ╱ │
C───D
加权图:A─⁴─B (边有权重,表示距离/成本)
│╲⁵ │
²│ ╲³│
│ ⁴╲│
C──D
网络中的应用:
- 无权图:跳数计算、连通性检测
- 加权图:延迟优化、带宽分配、成本最小化
环路与连通性
有环图:A → B → C (存在环路 A→B→C→A)
↑ ↓
└──────┘
无环图:A → B → C (无环路,树形结构)
↓
D
重要概念:
- 环路(Cycle):从某节点出发能回到自身的路径
- 连通图(Connected Graph):任意两点都有路径相连
- 强连通(有向图):任意两点都能互相到达
3. 图的存储结构
选择合适的存储结构对算法性能至关重要。
3.1 邻接矩阵(Adjacency Matrix)
定义 :用二维数组表示图,matrix[i][j] 表示节点 i 到 j 的边
python
# 无向图的邻接矩阵
# 0 1 2 3
matrix = [
[0, 1, 1, 0], # 0
[1, 0, 0, 1], # 1
[1, 0, 0, 1], # 2
[0, 1, 1, 0] # 3
]
# 加权图(数字表示权重,∞表示无边)
# 0 1 2 3
matrix = [
[0, 4, 2, ∞], # 0
[4, 0, ∞, 3], # 1
[2, ∞, 0, 5], # 2
[∞, 3, 5, 0] # 3
]
特点:
- 优点 :
- 判断两点间是否有边:O(1)
- 实现简单
- 适合稠密图(边多)
- 缺点 :
- 空间复杂度:O(V²)
- 遍历邻居:O(V)
- 稀疏图浪费空间
适用场景:
- 节点数量较少(V ≤ 1000)
- 边比较密集(E ≈ V²)
- 需要频繁判断两点间是否有边
3.2 邻接表(Adjacency List)
定义:用数组 + 链表表示图,每个节点存储其所有邻居
python
# 无权图的邻接表
graph = {
0: [1, 2], # 节点 0 的邻居是 1 和 2
1: [0, 3],
2: [0, 3],
3: [1, 2]
}
# 加权图的邻接表(存储邻居和权重)
graph = {
0: [(1, 4), (2, 2)], # 0→1 权重 4, 0→2 权重 2
1: [(0, 4), (3, 3)],
2: [(0, 2), (3, 5)],
3: [(1, 3), (2, 5)]
}
特点:
- 优点 :
- 空间复杂度:O(V + E)
- 遍历邻居:O(邻居数量)
- 适合稀疏图
- 缺点 :
- 判断两点间是否有边:O(邻居数量)
- 实现稍复杂
适用场景:
- 节点数量较多
- 边比较稀疏(E << V²)
- 需要频繁遍历邻居
3.3 边列表(Edge List)
定义:简单地用列表存储所有边
python
# 无权图
edges = [(0, 1), (0, 2), (1, 3), (2, 3)]
# 加权图(三元组:起点,终点,权重)
edges = [
(0, 1, 4),
(0, 2, 2),
(1, 3, 3),
(2, 3, 5)
]
特点:
- 优点 :
- 实现最简单
- 空间紧凑:O(E)
- 适合需要遍历所有边的算法
- 缺点 :
- 查找特定节点的邻居:O(E)
- 判断两点间是否有边:O(E)
适用场景:
- Kruskal 算法(需要遍历所有边)
- Bellman-Ford 算法
- 边数较少的图
3.4 存储结构对比
| 特性 | 邻接矩阵 | 邻接表 | 边列表 |
|---|---|---|---|
| 空间复杂度 | O(V²) | O(V + E) | O(E) |
| 判断边存在 | O(1) | O(度) | O(E) |
| 遍历邻居 | O(V) | O(度) | O(E) |
| 遍历所有边 | O(V²) | O(V + E) | O(E) |
| 适合稠密图 | ✅ | ❌ | ❌ |
| 适合稀疏图 | ❌ | ✅ | ✅ |
选择建议:
- 节点少、边多 → 邻接矩阵
- 节点多、边少 → 邻接表
- 需要遍历所有边 → 边列表
4. 图算法分类概览
根据解决的问题类型,图算法可以分为四大类:
4.1 最短路径算法
问题:找到两个节点之间的最优路径
起点 S,终点 T
S
/|\
/ | \
● ● ● 哪条路径最优?
\ | /
\|/
T
核心算法:
- Dijkstra:单源最短路径(无负权边)
- Bellman-Ford:单源最短路径(可处理负权边)
- SPFA:Bellman-Ford 的队列优化
- Floyd-Warshall:所有节点对的最短路径
- A*:启发式搜索最短路径
网络应用:
- OSPF、RIP 路由协议
- GPS 导航
- 网络延迟优化
4.2 最小生成树算法
问题:用最小成本连接所有节点
原始图: 最小生成树:
A A
/|\ / \
B-C-D B C-D
(边多成本高) (连接所有点,成本最低)
核心算法:
- Prim:从点开始扩展
- Kruskal:从边开始构建
网络应用:
- 网络拓扑设计
- 光缆铺设优化
- 生成树协议(STP)
4.3 图遍历算法
问题:系统地访问图中所有节点
BFS(广度优先): DFS(深度优先):
S S
/|\ |
● ● ●(一层层) ●
/|\
● ● ●(一条路走到底)
核心算法:
- BFS:广度优先搜索
- DFS:深度优先搜索
网络应用:
- 网络发现
- 拓扑排序
- 连通性检测
4.4 网络流算法
问题:在容量限制下最大化流量
源点 S,汇点 T
每条边有容量限制
S
/ | \
10 8 12 如何最大化到 T 的流量?
\ | /
T
核心算法:
- Ford-Fulkerson:增广路径算法
- Edmonds-Karp:BFS 实现的 Ford-Fulkerson
网络应用:
- 带宽分配
- 流量工程
- 网络拥塞控制