判断欧拉回路或路径需先验证连通性(忽略孤立点),再统计度数:回路要求所有非零度顶点度数为偶数;路径要求恰有两个奇度顶点且其余为偶数;其余情况不存在。

判断无向图是否存在欧拉回路或欧拉路径
核心就看每个顶点的度数(degree)和连通性。先用 DFS 或 BFS 检查图是否连通(忽略孤立点),再统计所有顶点的度数:
- 存在欧拉回路 ⇔ 所有非零度顶点度数为偶数,且图连通
- 存在欧拉路径(非回路) ⇔ 恰好两个非零度顶点度数为奇数,其余为偶数,且图连通
- 其余情况(如奇度点个数为 1、3+,或不连通)⇒ 不存在欧拉路径/回路
注意:全为孤立点(所有 degree[v] == 0)时,按定义视为存在平凡欧拉回路(空路径),但实际建图时常被忽略,需单独处理。
用 Hierholzer 算法构造欧拉回路
一旦确认存在欧拉回路,用 Hierholzer 是最稳定的选择——它基于栈式 DFS,避免递归爆栈,也天然支持边去重(vector<vector>></vector> 配合 used 标记或直接删边):
- 从任意非零度顶点开始(推荐选最小编号,便于调试)
- 每次沿未访问边走到邻居,把边标记为已用(或从邻接表中
pop_back()) - 当某顶点无可用出边时,将其加入结果栈,回溯
- 最终结果栈逆序即为欧拉回路顶点序列(若要边序列,记录每步经过的边)
示例关键逻辑(邻接表存边,边去重用 vector<vector bool>>></vector> 或更高效地用 vector<stack>></stack>):
vector<stack>> adj(n);
// 添加无向边 u-v:adj[u].push(v); adj[v].push(u);
vector<int> path;
stack<int> stk;
stk.push(start);
while (!stk.empty()) {
int u = stk.top();
if (adj[u].empty()) {
path.push_back(u);
stk.pop();
} else {
int v = adj[u].top(); adj[u].pop();
adj[v].pop(); // 无向图需双向删除
stk.push(v);
}
}
reverse(path.begin(), path.end());
</int></int></stack>
处理欧拉路径(非回路)的起点选择
欧拉路径必须从唯一的奇度点之一出发(两个奇度点时,起点是其中一个,终点是另一个)。不能随便选起点,否则 Hierholzer 会失败或输出错误路径:
- 遍历所有顶点,收集所有
degree[v] % 2 == 1的顶点到odd_nodes - 若
odd_nodes.size() == 2,起点必须设为odd_nodes[0](或任选其一) - 若
odd_nodes.size() == 0,才是欧拉回路,起点可任选非零度点 - 别忘了验证连通性——哪怕度数条件满足,但图不连通(如两个分离环),仍无欧拉路径
常见错误:没检查连通性,只看度数就调用 Hierholzer,结果只遍历了某个连通分量,漏边。
边重复、自环与多重图的注意事项
标准 Hierholzer 支持自环和多重边,但实现方式影响正确性:
- 自环
u-u贡献度数 +2,对奇偶性判断无干扰,但在邻接表中要加两次(adj[u].push(u)两次),删除时也要删两次 - 多重边(平行边)必须作为独立边处理:不能用
set或map去重;邻接表中每条边都要单独存储和删除 - 若用
vector<vector>></vector>存邻接表并配合used[i][j]标记边,索引管理易错;更推荐用vector<stack>></stack>或带 id 的边列表 +vector<bool> used</bool>
真正容易卡住的地方不是算法本身,而是图的输入建模——比如把无向边当成有向边添加一次,导致度数统计错误,后续全崩。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











