转自B站的一个视频【AgOHの数据结构】你真的了解链式前向星吗?,感谢大佬们~
引言
无论是树,无向图,有向图,我们都需要使用一种数据结构来保存“图”(我们的树可以看作是特殊的图~)的结构,这种结构就是我们的链式前向星。
我们如何存图?
1.邻接矩阵
如上图,使用邻接矩阵非常直观,但是它的空间复杂度达到了
O
(
n
2
)
O(n^2)
O(n2) 了。
2.邻接表
这种方法相比于邻接矩阵,它节约了很大的空间复杂度。实现邻接表常用的是使用vector
数组,但是用时候vector
数组的长度又会特别大。
若图是稀疏图,边很少,开二维数组a[][]很浪费;
若点很多(如10000个点),a[10000][10000]又会爆,只能用前向星做 (之前看过32M空间限制不要开超过 1000W 的int变量(C++))。
前向星的效率不是很高,优化后为链式前向星,直接介绍链式前向星。
所以,邻接表,邻接矩阵都不太好,大佬们就开发了一个新的存储图的数据结构——链式前向星。
3.链式前向星
其实,链式前向星就是一个邻接表。我们来对照看一下。
链式前向星在存储方面有两个部分组成。
(1)结构体E
struct E{
int to,w,next;
}Edge[maxm];
int tot,Head[maxn];
有三个变量:
to
:目的地,即边的destination;w
:边的权重,即weight;next
:下一个目的地的位置。
这三个变量,在前面的图中有体现,与邻接表进行了对应。
(2) Edge[maxm]
,tot
和Head[maxn]
建立一个内存池Edge[maxm]
,有一个计数器变量tot
指向内存池Edge[maxm]
最近的没有被使用的结点,它是一个空结点。
Head
数组是什么呢?
顾名思义,就是“头”(“首”),它在这个代码里面是Edge
数组的下标,代表位置,初始化全部为-1(或者其他自定义也行)。
(3) 遍历一个结点的所有边
我们来看一下如何遍历 一个结点u
所连向的所有的边的:
for(int i=Head[u];~i;i=Edge[i].next){
int v = Edge[i].to;
int w = Edge[i].w;
}
(4) 加边函数AddEdge
链式前向星还有一个非常重要的加边函数AddEdge
,那么它是如何运作的呢?
inline void AddEdge(int u,int v,int w){
Edge[tot].to = v;
Edge[tot].w = w;
Edge[tot].next = Head[u];
Head[u] = tot++;
}
它不是在“链表”的最后插入的,而是在最前面插入的。