1. 图论基础概念与核心价值
图论作为离散数学的重要分支,在计算机科学领域有着举足轻重的地位。我第一次接触图论是在解决一个社交网络好友推荐问题时,当时就被这种用点和线就能描述复杂关系的简洁美所震撼。图结构能够直观地表示各类实体间的关联,从社交网络的好友关系到城市间的交通路线,从编译器中的依赖关系到互联网的网页链接,无不体现着图的应用价值。
图的数学定义为G=(V,E),其中V是顶点集合,E是边集合。根据边的方向性可分为有向图和无向图;根据边是否带权重可分为加权图和非加权图。实际应用中,我们还会遇到一些特殊图类型:
- 完全图:每对顶点之间都有边连接
- 连通图:任意两个顶点间都存在路径
- 稀疏图/稠密图:根据边数与顶点数的比例划分
- 二分图:顶点可分为两个互不相交的集合
提示:初学者常混淆"路径"和"边"的概念。路径是由边连接的顶点序列,而边仅表示两个顶点的直接连接。比如A-B-C是一条包含两条边的路径。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 图的存储结构深度解析
2.1 邻接矩阵实现与特性
邻接矩阵是我最早掌握的图存储方式,它用二维数组直观地表示顶点间的连接关系。对于n个顶点的图,我们创建一个n×n的矩阵,matrix[i][j]的值表示顶点i到j的边信息(1/0表示是否存在,或存储权重值)。
c复制#define MAX_VERTEX 100
int adjMatrix[MAX_VERTEX][MAX_VERTEX];
void addEdge(int from, int to, int weight) {
adjMatrix[from][to] = weight;
// 若是无向图还需对称赋值
adjMatrix[to][from] = weight;
}
邻接矩阵的优势在于:
- 随机访问速度快:判断两点是否相邻只需O(1)时间
- 适合稠密图:空间利用率高
- 方便计算:某些图算法(如Floyd-Warshall)需要矩阵运算
但我在实际项目中发现它的明显缺陷:
- 空间复杂度O(V²)对稀疏图极其浪费
- 动态添加顶点困难(需要重新分配内存)
- 遍历邻居时需要扫描整行,即使邻居很少
2.2 邻接表实现与优化
为解决邻接矩阵的空间浪费问题,邻接表应运而生。它使用链表存储每个顶点的邻居,空间复杂度降至O(V+E)。下面是C++实现示例:
cpp复制#include <vector>
#include <list>
using namespace std;
class Graph {
private:
int V; // 顶点数
vector<list<pair<int, int>>> adj; // 邻接表(目标顶点, 权重)
public:
Graph(int V) : V(V), adj(V) {}
void addEdge(int u, int v, int weight) {
adj[u].emplace_back(v, weight);
// 无向图需双向添加
adj[v].emplace_back(u, weight);
}
};
在实际编码中,我总结了几点优化经验:
- 使用vector代替原生数组便于动态扩展
- pair存储邻居和权重,避免额外结构体
- 对于确定无权的图,可简化为vector<list
> - C++中优先选用emplace_back减少临时对象创建
邻接表的优势在遍历操作中尤为明显。以广度优先搜索(BFS)为例:
python复制def bfs(graph, start):
visited = [False] * len(
