图的存储与遍历

直接存边法

做法

建立三个数组 u[N]v[N]w[N],对于每一次读入的起点,出点和权值存储即可。

初始化

1
2
struct Edge { int u, v, w; };
vector<Edge> graph;

存储

1
2
3
4
void add(int a, int b, int c)
{
graph.push_back({a, b, c});
}

遍历

1
2
3
4
5
6
7
8
9
void dfs(int ver)
{
if (vis[ver]) return;
vis[ver] = true;

for (auto t : graph)
if (t.u == ver)
dfs(t.v);
}

复杂度

查询两点之间是否连通:O(m)O(m)

遍历一个点所有出边:O(m)O(m)

遍历整张图:O(n×m)O(n \times m)​。

适用于最小生成树 Kruskal 算法

邻接矩阵

做法

在点的个数较小的情况下,建立一个二维数组 g[N][N],让 g[u][v] 存储从 uu 点到达 vv 点的权值。

初始化

1
2
3
4
5
6
int g[N][N];

memset(g, 0x3f, sizeof g);

for (int i = 1; i <= n; i ++)
g[i][i] = 0;

存储

1
2
3
4
void add(int a, int b, int c)
{
g[a][b] = g[b][a] = c;
}

遍历

1
2
3
4
5
6
7
8
9
void dfs(int ver)
{
if (vis[ver]) return;
vis[ver] = true;

for (int v = 1; v <= n; v ++)
if (g[ver][v] != INF)
dfs(v);
}

复杂度

查询两点之间是否连通:O(1)O(1)

遍历一个点所有出边:O(n)O(n)

遍历整张图:O(n2)O(n ^ 2)​。

空间复杂度:O(n2)O(n^2)

适用于 Floyd 算法 等点数小的稠密图。

邻接表

通过 C++ 的 STL 容器 vector 定义一个支持动态增加元素的二维数组,从而减少储存和遍历非边的时间和空间。

初始化

1
2
struct Edge { int ver, val; }
vector<Edge> g[N];

存边

1
2
3
4
5
void add(int a, int b, int c)
{
g[a].push_back({b, c});
g[b].push_back){a, c});
}

遍历

1
2
3
4
5
6
7
8
void dfs(int ver)
{
if (vis[ver]) return;
vis[ver] = true;

for (auto y : g[ver])
dfs(y.ver);
}

复杂度

遍历整张图:O(n+m)O(n + m)

空间复杂度:O(m)O(m)​。

遍历一个节点出边的时间复杂度依情况而定。

适用于一切的图,但是由于 vector 的常数较大,实际运行效率不如链式前向星(但是好理解)。

链式前向星

首先定义一个表头数组 h[N],使得图上所有的点都对应一个表头。我们让每一条边都有一个编号 idx ,接着定义三个数组 e[N]ne[N]w[N]

对于 e[idx],表示第 idxidx 条边的出度。

对于 w[idx],表示第 idxidx 条边的权值。

对于 ne[idx],表示第 idxidx 条边的入度所对应的下一条边的编号。

每一次增加了一条边后,idxidx 也要相应的增加。

初始化

1
2
3
4
5
const int N = 2e5 + 9, M = 2 * N;    // N 表示总点数,M 表示总边数

int h[N], e[M], w[M], he[M], idx;

memset(h, -1, sizeof h); // 先将表头数组初始化为 -1

存储

1
2
3
4
void add(int a, int b, int c)
{
e[++ idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx;
}

遍历

1
2
3
4
5
6
7
8
void dfs(int ver)
{
if (vis[ver]) return;
vis[ver] = true;

for (int i = h[ver]; ~i; i = ne[i]) // ~i 表示 i != -1
dfs(e[i]);
}

复杂度

遍历整张图:O(n+m)O(n + m)

空间复杂度:O(m)O(m)​。

遍历一个节点出边的时间复杂度依情况而定。