图论的存储
- 邻接表
- 邻接矩阵(一般不用)
邻接表
结构体数组实现
- 缺点:如果使用结构体的话,
node结构体初始化很慢。
cpp
// common one
vector<list<int>>g;
// another type
typedef struct node{
int val;
int dist;// 如果需要节点到某点的距离的话
}
vector<list<node>>g;
- 插入操作
cpp
q.push_back(item)
纯数组实现(y总版本)
- 邻接表定义:
- h代表链表头指针,指向v,nxt数组中的每一个节点
- v代表某一个边终点节点 的具体值,nxt代表指向的边。注意这两个数组其实都是代表边 ,可能会出现1->3,2->3,3号节点对应v和nxt中不同的位置的情况!
- v和nxt的大小等于边数!
- len代表总共有多少边。
cpp
int h[100009], v[100009], nxt[100009], len = 0;
- 插入操作
cpp
void insert(int x,int y) {
len++;
v[len] = y;
nxt[len] = h[x];
h[x] = len;
d[y]++;
}
- 容易出错的操作:搜索时我们假定得到的是节点编号 ,但是我们nxt和h指向的是该节点的实际存储位置。
cpp
for (int i = h[cur]; i != -1; i = nxt[i]) {
int node = v[i];
d[node]--;
if (!d[node]) {
q.push(node);
}
}
DFS
例题
- 846. 树的重心:可以使用动态规划的思想进行优化。
cpp
int n,ans=INT_MAX;
int h[100009], v[200009], nxt[200009], len = 0, visited[100009];
// 返回当前节点的连通图数量
int dfs(int cur) {
visited[cur] = 1;
int res = 0, sum = 0;
for (int i = h[cur]; i != -1; i = nxt[i]) {
int node = v[i];
if (!visited[node]) {
int tmp = dfs(node);
res = max(res, tmp);
sum += tmp;
}
}
res = max(res, n - sum - 1);
ans = min(ans, res);
// 根据动态规划的思想考虑当前节点的连通图节点数量。
return sum + 1;
}
void insert(int x, int y) {
len++;
v[len] = y;
nxt[len] = h[x];
h[x] = len;
}
void solve() {
cin >> n;
memset(h, -1, sizeof h);
for (int i = 1; i <= n - 1; i++) {
int a, b;
cin >> a >> b;
insert(a, b);
insert(b, a);
}
dfs(1);
cout << ans;
}
BFS
例题
- 847. 图中点的层次:注意h和v数组的含义就行。
cpp
void bfs() {
q.push(1);
visited[1] = 1;
while (q.size()) {
int cur = q.front();
if (cur == n) {
cout << dist[cur];
return;
}
q.pop();
for (int i = h[cur]; i != -1; i = nxt[i]) {
int node = v[i];
if (!visited[node]) {
visited[node] = 1;
dist[node] = dist[cur] + 1;
q.push(node);
}
}
}
cout << -1;
}