图的存储与围绕某一结点的遍历
稀疏矩阵怎么存储?图太大了不能用二维数组的邻接表怎么办?该如何遍历与某一结点相连的所有边?
我们将围绕这个图进行展开。
设该图的输入如下:
/*
1 2
2 3
3 4
1 3
4 1
1 5
4 5
*/
前向星
前向星是一种特殊的边集数组,我们把数组中的每一条边按照起点从小到大排序,如果起点相同,则按照终点从小到大排序,并记录下以某个点为起点的所有边中第一条边的位置以及所有边的数量。
len[i]:以i
为起点的所有边的数量。
head[i]:数组经过排序后,以i
为起点的所有边中第一条边在数组中的下标。
如上图, 对边集排序后我们可以得到:
// 数组下标: 1 2 3 4 5 6 7 (方便起见,我们从1开始)
// 起 点:1 1 1 2 3 4 4
// 终 点:2 3 5 3 4 1 5
那么其对应的len数组和head数组即为:
// 1 2 3 4 5
// head: 1 4 5 6 (INF/0) (不存在时可以设置一个不会在图中出现的值)
// len : 3 1 1 2 0
这样我们就得到了前向星。
链式前向星
在使用前向星的时候,我们需要排序,而链式前向星则不需要。在实际使用过程中链式前向星也更为广泛。
首先我们建立结构体:
// e[i]表示输入的第i条边
struct Edge{
int next; // 记录与e[i]同起点的下一条边的数组下标
int to; // 记录e[i]的终点
int w; // 记录第i条边的权重值
}e[N];
这样我们得到了所有边的信息。
但是当我们需要遍历某个结点的所有边时,仅仅有这些还不够,我们还需要一个关键性的数组:head
。
head
数组用来记录以i
为起点的最后一条边在e
数组中的数组下标。一般初始化为-1
。
这样我们需要的东西就齐全了。接下来是存储:
int cnt = 0;
void add(int u, int v, int w) {
e[cnt].w = w;
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt++;
}
我们按照上图进行模拟,得到如下结果:
e下标 | to | next | head下标 | head |
---|---|---|---|---|
0 | 2 | -1 | 1 | 0 |
1 | 3 | -1 | 2 | 1 |
2 | 4 | -1 | 3 | 2 |
3 | 3 | 0 | 1 | 3 |
4 | 1 | -1 | 4 | 4 |
5 | 5 | 3 | 1 | 5 |
6 | 5 | 4 | 4 | 6 |
通过表可以看出,head存储的是最后一条边,这样的话遍历的时候就是倒着遍历的,不过并不影响结果的正确性。
遍历结点u
的操作就是这样的:
for (int i = head[u]; ~i; i = e[i].next)
觉得不错的话记得点个赞呀~~
参考资料
https://blog.csdn.net/acdreamers/article/details/16902023