邻接表存图法
也才刚刚学会这个不久,记一下防止忘记了。
邻接表适合存储稀疏图,它不会像邻接矩阵一样浪费大量的空间,而是把所有的边存在一个表里面,在需要的时候,就遍历该表,然后找出自己想要的边。存储边的方法和邻接矩阵其实是一样的,邻接矩阵里面,e[a][b]=1就表示从点A到点B有一条距离为一的边(两点确定一条边),那么邻接表也是大同小异,我们需要一个结构体数组作为边表,如下:
struct edge{
int u,v,next;
}e[maxm];
其中,u表示从点u出发,v表示点u到达的点。读入的时候可以直接存储e[i].u,e[i].v,就代表在表e的第i个位置存了可以从点u到点v的边,当然你如果想表示距离的话,不介意再加入一个结构体成员dis,到时候多存一个e[i].dis就好了。
存储的表已经有了,但是怎么去存储呢?
在这里,我先讲讲需要什么工具去存储吧!我们创建一个可以存储两个点(一条边)的函数(具体内容怎么写一会就告诉你),曰:addedge,同时我们再创建一个一维数组叫head,建立一个指针js,js初始化为0。
首先,每一个点都有自己的出边,那么我们的邻接表就是拿来统计每一个点的出边的。但是一个点有很多出边对吧,所以我们使用链表来储存每一个点的所有出边。这个时候,你之前创建的结构体成员next就派上了用场,next的用途就是指向这个点的上一条出边。额…会有点点难理解,我在第一次学习的时候就是这样。要不我通过它存一条边的流程来解释吧:
一开始存边的时候,假设我们存点6的第一条出边(什么叫第一条呢?我们在读取你输入的数据的时候会有先后,第一个读入的边习惯称作第一条),那么我们就命令head[6]的内容指向e中的一个位置,我们假设是在e[8]里面,在这个e[8]里面自然就存在三个成员:u,v,next吧。那么出发点——显然是u这个成员,也就是点6,那就赋值为6,到那个点呢?假设我们输入的是7,那v就是7了吧。但是next有什么用?大家想想,倘若点6还有出边,怎么办?我们要把next指向点6的上一条出边在e中存储的位置,这样就可以根据这一条找回上一条了嘛,假设是e[9],还是像刚刚一样把出发点(点6),终点,都填进去。倘若点6没有出边了呢?那就让最后一个点的next为零就好了。
按照我的描述,代码就会是酱紫:
void addedge(int u,int v){
e[++js].u=u;
e[js].v=v;
e[js].next=head[u];
head[u]=js;
return;
}
那么,我们现在用实际例子模拟一遍流程。
首先,我们输入数据如下:
- 5 7
- 1 2
- 1 4
- 1 5
- 2 3
- 3 5
- 4 1
- 5 2
其实就是这幅图:
然后我们初始化都是0。
第一行5和7不是点,表示总点数和边数。接下来才是点。
按照输入的数据,第一条边是1,2。所以我们执行 e[++js].u=u; 语句和 e[js].v=v; 语句。接着执行e[js].next=head[u];语句,就是把点1的第一条出边的位置指向e[js]的next,此时next成员等于0,就是head[1]=e[1].next。然后执行head[u]=js;即head[1]=1得到如下结果:
按照输入的数据,第二条边是1,4。所以我们执行 e[++js].u=u; 语句和 e[js].v=v; 语句。接着执行e[js].next=head[u];语句,就是把点1的第二条出边的位置指向e[2]的next,此时next成员等于1,然后执行head[u]=js;这你可以把它想象成一个纠正的过程,原本的e[1].next我们不动,我们反而把head的指向内容给改了,改成了2。因为js一直在变,而我们则是把head[u]=js;所以我们的head[u]一直都紧紧跟着最后一条出边。而最后一条出边可以根据next一步一步找到第一条!我们之所以先不用js更新head[u]是因为我们要让新加入的边的next指向上一条边,然后再用js更新head[u],使head[u]指向当前的边。存入第二条边以后就会酱紫:
按照这个路子,我们把点一的所有出边都统计完,就会是这样子:
接下来开始存点二的,js++照例,e[++js].u=u; 语句和 e[js].v=v; 语句也是一如既往地执行,然而head[u]的u就不是1了(废话),当执行e[js].next=head[u];的时候,其实就是把e[4].next=head[2],而head[2]等于0。这样,我们等于又建立了一个新的链表关系,再点2上面添加边,而与点1的没有任何关系了,接下来就不演示了。存完后就会是下面这样:
仔细观察,你会发现需要寻找一个点的所有出边的时候,只要根据head就可以回溯到该点的所有出边,而这就是邻接表了。建议自己模拟一遍,可以加深理解。附赠一个输入的代码:
for(int i=1;i<=s;i++){
cin>>a>>b;
addedge(a,b);
}
手软,打了这么多字…