邻接矩阵中顶点i的出度为第i行非零元个数,入度为第i列非零元个数;邻接表需预维护in_degree和out_degree数组以避免查询时遍历,注意重边、自环及稀疏图中哈希表的初始化问题。

用邻接矩阵计算入度和出度最直观
邻接矩阵天然适合统计每个顶点的入/出关系:第 i 行的非零元素个数就是顶点 i 的出度,第 i 列的非零元素个数就是入度。注意是否带权——若为有向图且边权为 0 是合法值,则不能用 != 0 判断,得用 graph[i][j] != INF(INF 表示无边)。
常见错误是混淆行列含义,尤其在手写循环时把 j 当成行、i 当成列;还有人默认矩阵对称,忘了有向图的邻接矩阵一般不对称。
- 初始化矩阵时,用
vector<vector>> graph(n, vector<int>(n, 0))</int></vector>或INT_MAX表示无边 - 添加有向边
u → v:设graph[u][v] = 1(或权重) - 计算顶点
v的出度:count_if(graph[v].begin(), graph[v].end(), [](int x) { return x != 0; }) - 计算入度:遍历所有
i,统计graph[i][v] != 0的个数
邻接表下需额外维护度数组
邻接表本身只存出边,查出度只需看 adj[v].size();但查入度必须遍历所有顶点的邻接表,效率是 O(V + E)。实际项目中,如果频繁查入度,建议在建图时同步更新两个数组:in_degree[v]++ 和 out_degree[u]++。
容易忽略的是重边和自环:若允许多条 u→v 边,每次加边都要累加;自环 v→v 同时贡献入度和出度各 1。
- 建图时每加一条
u → v,执行out_degree[u]++和in_degree[v]++ - 不要等查询时再遍历——除非图是静态且只查一两次
- 初始化
in_degree和out_degree为全 0 的vector<int>(n)</int>
使用 std::map 或 std::unordered_map 存储稀疏图时的注意事项
当顶点编号不连续或范围极大(如 ID 是字符串或大整数),常用哈希表模拟邻接表。此时无法直接用下标访问,得用 for (auto& [neighbor, weight] : adj[u]) 遍历出边;入度则必须预建反向映射 in_adj[v],或用 map<int int> in_degree</int> 并在加边时更新。
典型坑是忘记初始化未出现过的顶点:比如只有边 1→2 和 3→2,那么 in_degree[2] 是 2,但 in_degree[1] 和 in_degree[3] 可能根本没被插入 map,直接访问会意外创建键值对(operator[] 的副作用)。
- 查入度前先用
in_degree.count(v)判断是否存在,或统一初始化所有可能顶点 - 用
in_degree.at(v)替代in_degree[v]避免静默插入 - 若顶点集未知,建图后可用
set收集所有出现过的顶点再补全度数组
处理带权图、多重边和自环的实际判断逻辑
入度和出度的定义与边权无关,只取决于“存在性”。但代码里怎么定义“存在”很关键:若用 0 表示无边,那权值为 0 的边就会被漏掉;若用 -1 表示无边,又和负权边冲突。更鲁棒的做法是用单独的布尔矩阵/集合,或用 optional<int></int>(C++17+)。
自环 v→v 在大多数图算法中算作一条出边和一条入边,但有些场景(如 DAG 判定)会显式禁止。务必确认业务需求是否计入自环。
- 有向图中,自环使
in_degree[v]和out_degree[v]各 +1 - 若用邻接矩阵且支持负权,推荐用
numeric_limits<int>::max()</int>作 INF - 多重边:若需统计边数而非邻接点数,度数组就该累加次数,而不是仅标记存在
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











