图的存储
邻接矩阵
原理
使用一个二维数组 mat
来存边,其中 mat[u][v] = w
表示结点 \(u,v\) 间存在一条权值为 \(w\) 的边
复杂度
设图有 \(n\) 个点 \(m\) 条边
- 查询是否存在某条边 \(O(1)\)
- 遍历一个点的所有出边 \(O(n)\)
- 遍历全图 \(O(n^2)\)
- 空间复杂度 \(O(n^2)\)
优点与缺点
- 简易且可以在 \(O(1)\) 的时间里查询一条边是否存在
- 空间复杂度高,只适合于稠密图
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 1000 + 5;
int n, m;
int mat[MAX_N][MAX_N];
int main()
{
cin >> n >> m;
for(int i = 1; i <= m; i++){
int u, v, w;
cin >> u >> v >> w;
mat[u][v] = mat[v][u] = w;
}
return 0;
}
邻接表
原理
使用 vector<int> e[]
来存边,e[u]
存储的是 \(u\) 的出边的信息(终点,边权等)
复杂度
- 查询是否存在 \(u\) 到 \(v\) 的边 \(O(d^+(u))\)
- 遍历结点 \(u\) 的所有出边 \(O(d^+(u))\)
- 遍历全图 \(O(n+m)\)
- 空间复杂度 \(O(m)\)
优点与缺点
- 适用于稀疏图,空间复杂度小
- 查询一条边是否存在时效率较低
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 5000 + 5;
struct node{
int v, w;
};
vector<node> e[MAX_N];
int n, m;
void add(int u, int v, int w)
{
node a;
a.v = v;
a.w = w;
e[u].push_back(a);
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= m; i++){
int u, v, w;
cin >> u >> v >> w;
add(u, v, w);
}
return 0;
}
链式前向星
原理
本质上是用链表(数组)实现的邻接表
复杂度
同邻接表
优点与缺点
- 有邻接表的优点,且效率较高
- 查询一条边时效率较低
代码
#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 5000 + 5;
struct node{
int u, v, w;
int next;
}e[MAX_N];
int n, m;
int cnt;
int head[MAX_N];
void init()
{
cnt = 0;
memset(head, -1, sizeof(head));
}
void add(int u, int v, int w)
{
e[cnt].u = u;
e[cnt].v = v;
e[cnt].w = w;
e[cnt].next = head[u];
head[u] = cnt++;
}
int main()
{
cin >> n >> m;
init();
for(int i = 1; i <= m; i++){
int u, v, w;
cin >> u >> v >> w;
add(u, v, w);
}
return 0;
}
对结点 \(u\) 的出边遍历
for(int i = head[u]; i != -1; i = e[i].next) {
......
}