链式前向星详解🔥

2,358 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情

前向星的名字很好听,但它并不是一颗真正星星呀。 它是一种很特别的边集数组,数组里面的边,以起点为下标,按照序号升序来排序。同起点的边,按照终点升序排序。

构建前向星我们需要两个数据结构

边数组

这个我们构建一个结构体

struct edge{
	int to,dis,last;
}e[2333];

对于每条边有三个属性

  1. to: 边的终点

  2. last: 边的起点连接的上一条边

  3. dis :边的长度

PS:我们讲过,边集合数组里面的边是按照起点从小到大排序的,而且一个起点可能连接着许多条边,所以一条边的 last属性就是 起点连接的上一条终点序号更小的边

由上图我们知道,一号点连接着三个终点,那么就产生了三条边。这些边的起点都是一号点,因此他们按照终点升序来排序。另外,每条边的 last属性讲的是该点连接的上一条终点序号更小的边,倘若该边就是起点连接的第一条边,那么这条边的 last 可以设为-1或者0.(边序号默认从1开始)

边序号起点序号终点序号起点的上一条边序号
1120
2131
3142

我们通过上面的表格可以发现:起点1的上一条边序号会随着我们边的增加进行更新 0==>1==>2 。当边3创建完毕后,我们点1的最后一条出边就是边3了

上面我们讲了同一个起点的边集合情况,接下来我们讲不同起点应该怎么办。

我们引入第二个数据结构

next数组

其实这个数组存的就是 每个点连接的最后一条出边的序号

它以 点的序号为下标,该点连接的最后一条边序号为值。

每当一个点连接某个点,产生新边后,这个点的next数组就更新为新边的序号

由上图我们知道, 点1的最后连接的出边为边3, 点2的最后连接的出边为边5, 点3的最后连接的出边为边6 点4的最后连接的出边为边8, 点5,6,7均无出边。 因此我们可以把上面图的next数组作出:

next[1]3
next[2]5
next[3]6
next[4]8
next[5]0
next[6]0
next[7]0

接下来我们按照链式前向⭐来构建这张图

图中带黑框的数字是边的长度

🆗 我们再来回顾下 ,我们构建前向星用了两个结构。

第一个

第二个

然后我们构建前向星的边还会用到一个加边函数add , 这个就是我们构建前向星的本质

Add函数

void add(int u,int v,int d){
    e[++cnt].to=v;
    e[cnt].d=d;
    e[cnt].last=next[u];
    next[u]=cnt;
}

在上面这个函数中,cnt变量指的就是边的序号,它从1开始 ,每构建一条新边,cnt就增加1.

我们的next数组的存的是该点连接的最后一条出边的序号,因此每当某个点构建一条新边时,我们要更新它的next存的值。至于我们这条边的last属性,自然就是在构建这条边之前,尚未更新的next数组啦。

建图

现在我们给出的数据形式是这样的:

第一行给出两个整数n m

接下来m行,每行给出三个整数 u ,v,d 分别代表一条边的起点 ,终点,长度

数据如下:

5 8

1 2 3

1 3 4

2 3 1

2 4 6

3 4 7

3 5 10

4 3 2

4 5 5

我们现在按顺序来构建每一条边

边序号起点终点长度e[]数组属性next[]更新
<1>123e[1]:to=2,d=3;last=0next[1]:0=>1
<2>134e[2]:to=3,d=4;last=1next[1]:1=>2
<3>231e[3]:to=3,d=1;last=0next[2]:0=>3
<4>246e[4]:to=4,d=6;last=3next[2]:3=>4
<5>347e[5]:to=4,d=7;last=0next[3]:0=>5
<6>3510e[6]:to=3,d=10;last=5next[1]:5=>6
<7>432e[7]:to=3,d=2;last=0next[1]:0=>7
<8>455e[8]:to=5,d=5;last=4next[1]:4=>8