【模板】图的存储与遍历
图的存储与遍历
直接存边法
做法
建立三个数组 u[N]
,v[N]
,w[N]
,对于每一次读入的起点,出点和权值存储即可。
初始化
1 | struct Edge { int u, v, w; }; |
存储
1 | void add(int a, int b, int c) |
遍历
1 | void dfs(int ver) |
复杂度
查询两点之间是否连通:。
遍历一个点所有出边:。
遍历整张图:。
适用于最小生成树 Kruskal 算法。
邻接矩阵
做法
在点的个数较小的情况下,建立一个二维数组 g[N][N]
,让 g[u][v]
存储从 点到达 点的权值。
初始化
1 | int g[N][N]; |
存储
1 | void add(int a, int b, int c) |
遍历
1 | void dfs(int ver) |
复杂度
查询两点之间是否连通:。
遍历一个点所有出边:。
遍历整张图:。
空间复杂度:。
适用于 Floyd 算法 等点数小的稠密图。
邻接表
通过 C++ 的 STL 容器 vector
定义一个支持动态增加元素的二维数组,从而减少储存和遍历非边的时间和空间。
初始化
1 | struct Edge { int ver, val; } |
存边
1 | void add(int a, int b, int c) |
遍历
1 | void dfs(int ver) |
复杂度
遍历整张图:。
空间复杂度:。
遍历一个节点出边的时间复杂度依情况而定。
适用于一切的图,但是由于 vector
的常数较大,实际运行效率不如链式前向星(但是好理解)。
链式前向星
首先定义一个表头数组 h[N]
,使得图上所有的点都对应一个表头。我们让每一条边都有一个编号 idx
,接着定义三个数组 e[N]
,ne[N]
,w[N]
。
对于 e[idx]
,表示第 条边的出度。
对于 w[idx]
,表示第 条边的权值。
对于 ne[idx]
,表示第 条边的入度所对应的下一条边的编号。
每一次增加了一条边后, 也要相应的增加。
初始化
1 | const int N = 2e5 + 9, M = 2 * N; // N 表示总点数,M 表示总边数 |
存储
1 | void add(int a, int b, int c) |
遍历
1 | void dfs(int ver) |
复杂度
遍历整张图:。
空间复杂度:。
遍历一个节点出边的时间复杂度依情况而定。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Thy's Blog!