3

链式向前星

 2 years ago
source link: https://tomotoes.com/blog/chain-forward-star/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

链式向前星

2017-11-22
阅读本文可能花费您 3 分钟

这是一种神奇的数据结构。

听说是某个高中 Oi 菊苣发明,%%%

有的时候有的图可能比较稀疏而且点数较多,邻接矩阵存不下,所以就要用到邻接表。 邻接表用 vector 数组比较方便,但是 vector 比较慢。所以就有了链式向前星。

通过 Head 可以找到一个点的所有边,可以把 Head 理解为:链表的有实际含义的头节点

Head[N]永远保存最后一次输入的 N 点数组的下标值,

Head[N]=idx; 意思是,保存 N 点的数组的下标值

而 Next 保存变化中的 Head,但不保存最后一次的 Head

Edge[i].Next=Head[N]; Head[N]=idx++; 从而 Head 与 Next 数组实现链式向前星的整个过程,

Head 相当于链表的有实际含义的头节点 Next 保存链表中的节点,但值得注意的是 Next 与 Head 都是通过保存下标值的方式实现的 相当于:索引式链表

End 为终点,Value 为权值,先不提 而 Next 就相当于链表中的节点的位置,而没有头节点 Head ,是无法提取的。 保存下标值的方式很有趣,虽然开始理解起来有点怪。

int i=Head[S]; 此时 i 为最后一次保存 S 点数组的下标值,也就是最后一次输入的 S 点数据 Edge[i].End 便为最后一次输入 S 点的终点,Value 也是同理,而 S 作为出发点,不再多提

之后很关键,i=Edge[i].Next,要知道,每次的 Edge[i].Next 都是由 Head 变化而来 意思就是,i=Edge[i].Next,此后的 i 为倒数第二次输入 S 点数组的下标值! i=Edge[Head[S]].Next;之后 i=Edge[Edge[Head[S]].Next;].Next; 从而反复循环,直到,下一条边为 0 时,便是最后一次输入的 S 点的数组的下标值 因为 最开始时,Edge[i].Next=Head[S]=0;

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5;
struct Node{
int End;//保存一个边的终点
int Next;//保存一个点(起点)的 除了最后一条(输入的顺序)之外的所有边的下标值
int Value;//保存一条边的权值
Node(){}
Node(int a,int b,int c):
End(a),Next(b),Value(c){}
}Edge[maxn];
bool Vis[maxn];
int Head[maxn];//Head 数组 为边的索引
int Idx;
queue<int>Map;
inline void AddEdge(int Start,int End,int Value){
Edge[Idx]=Node(End,Head[Start],Value);
Head[Start]=Idx++;
}
inline void Init(){
Idx=1;
memset(Edge,0,sizeof(Edge));
memset(Vis,false,sizeof(Vis));
int N,M,x,y,z;
scanf("%d%d",&N,&M);
while(M--){
scanf("%d%d%d",&x,&y,&z);
AddEdge(x,y,z);
AddEdge(y,x,z);
}
int Start;
scanf("%d",&Start);
Vis[Start]=true;
Map.push(Start);
}
inline void Traverse(){
while(!Map.empty()){
int Start=Map.front();
Map.pop();
for(int i=Head[Start];i;i=Edge[i].Next){
printf("%d->%d=%d\n",Start,Edge[i].End,Edge[i].Value);
if(!Vis[Edge[i].End]){
Map.push(Edge[i].End);
Vis[Edge[i].End]=true;
}
}
}
}
int main(){
Init();
Traverse();
return 0;
}
/*
输入样例
5 5
1 2 3
2 3 4
3 4 5
4 5 6
5 6 7
1
*/

优点:不会浪费数据空间; 缺点:无法直接判断两个点是否是邻接点 链式向前星是一个很不错的数据结构,利用数组索引特性,加上其他权值,存储了整个图。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK