「学习笔记」存图


我们既然正在学习 图论 ,那么我们就 必须 掌握几种 存图方式

PS:本文记点 \(u\)出度\(degree^{+(u)}\)

1. 直接存图

用一个 结构体数组 \(edge_i\) 来存图,结构体中包含这条边 \((u,v,w)\)源点、汇点,权值

显然,此方法 空间复杂度\(O(m)\)查询某条边的时间复杂度\(O(m)\)

2. 邻接矩阵

邻接矩阵是一种 方便且容易理解 的存图方式。

其本质是一个数组 \(grath_{i,j}\space(1\le i,j\le n)\) ,表示从点 \(i\) 到点 \(j\) 的权值。

显然,邻接矩阵的 空间复杂度\(O(n^2)\)

如此之高的空间复杂度,只要 \(n\ge 10^4\)内存就会超出限制 ,而且也不能应用在 有重边 的情况下。

但是,

稠密图 ( \(m\approx n^2\) ) ,下,它比 直接存图的方式更优 ,因为要查询某一条边,两者的时间复杂度分别为 \(O(m)\)\(O(1)\)

而接下来介绍的方法,比前两者 都更优秀

3. 邻接表 (链式前向星)

这种方法使用一个支持动态增加元素的数据结构构成的数组, 如使用 struct edge {int v,w,nxt;} grath[MAXM]; 来存边,其中 grath[cnt] 存储的是第 \(cnt\) 条边的相关信息 (去向、权等)。

链式前向星 就是用 链表 实现的 邻接表

此方式的时空复杂度 极其优秀

查询是否存在边 \((u,v)\)\(O(degree^{+(u)})\) ,可优化到 \(O(\log(degree^{+(u)}))\)

遍历点 \(u\) 的所有出边 (即以点 \(u\) 为源点的边): \(O(degree^{+(u)})\)

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

空间复杂度: \(O(m)\)

总结:

如果是在 稠密图且没有重边 的情况下,可以使用 邻接矩阵

如果要像 \(Kruskal算法\) 一样按照 边权大小 进行排序,则 必须使用直接存图

一般情况下,请使用 邻接表链式前向星