图的存储常见的就两种:邻接表和邻接矩阵。链式前向星是介于两者之间的一种图的存储方式.
结构体存的是边的信息,u,v分别是边的起始点,next指针指向的是前一次存入的边的序号,如果前面没有序号,则存入-1;
重点在于引入了一个 head[ ] 数组,利用 head[ ] 数组抽象的构造出了邻接表的一种存储方式。
head[u]存储的是最后一条存入u节点的边的序号,之所以是最后一条边是因为在构造的过程中不断的将上一轮称之为最后一条边的序号转移,新来边的序号去覆盖head[u]。这种方法有点像邻接表的头插法的构造方法。
因为 head[u] 已经拿到了最后一次存入u节点的边的序号,因此可以访问最后一条边e[ head[u] ].u、e[ head[u] ].v ,然而e[ head[u] ].next存储的是相同节点u的前一条边,因此就可以很顺利的访问到相同节点所有边。
链式前向星算法也没有很明显的优势,因此用的也不是很多。算法的复杂度因为需要遍历每个节点以及相邻边,因此是O(n+m)。
贴上代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define SIZE 1000
using namespace std;
int n,m; //记录n个节点,m条边
int head[SIZE]; //记录当前节点所存储的最后一条边的序号
int ecnt; //记录边的个数
struct edge
{
int u,v;
int next; //同一节点只向下一条边
}e[SIZE];
void make_edge(int from,int to) //有向图构造边
{
e[ecnt].u = from;
e[ecnt].v = to;
e[ecnt].next = head[from]; //将上一轮的最后一个节点转移,新的节点为最后一个节点
//为-1的话则是当前节点所有边的终结
//有点像头插发构建链表
head[from] = ecnt ++; //存储from节点最后插入的节点的边的序号
}
void make_undirected_edge(int from,int to) //无向图构造边
{
make_edge(from,to);
make_edge(to,from);
}
int main()
{
freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF)
{
int u,v;
ecnt = 0;
memset(head,-1,sizeof(head));
for(int i = 0 ; i < m ; i ++)
{
scanf("%d%d",&u,&v);
make_edge(u,v);
}
for(int u = 1 ; u <= n ; u ++) //遍历以u节点为起点的所有边
{
for(int i = head[u] ; i != -1 ; i = e[i].next)
{
cout<<e[i].u<<"->"<<e[i].v<<endl;
}
}
}
}
1256

被折叠的 条评论
为什么被折叠?



