数组模拟的邻接表——链式前向星

之前一直使用vector存储邻接表,但是由于一本通疯狂使用数组模拟的邻接表,加上出现了一些题目使我难受。特此整理一下这种存储图的方式。

1.前向星是怎么存图的


一种数据结构,以储存边的方式来存储图。构造方法如下:读入每条边的信息,将边存放在数组中,把数组中的边按照起点顺序排序,前向星就构造完了。通常用在点的数目太多,或两点之间有多条弧的时候。一般在别的数据结构不能使用的时候才考虑用前向星。除了不能直接用起点终点定位以外,前向星几乎是完美的。
—— 百度百科

使用vector存图的时候我们是通过保存邻接点,来实现图的存储。
是这个亚子的:
在这里插入图片描述前向星保存的却是边,将边编上号,然后保存下来,-1表示没有边了 和 null的意义一致。
是这个亚子:
在这里插入图片描述

2.链式前向星


Ⅰ.结构体
struct Edge{
	int to;//第i条边的终点 
	int nex;// 表示与第i条边同起点的下一条边的存储位置
	int w;//边的权值 
}; 
Ⅱ.edge[]数组和head[]数组
edge[]数组

保存边的边集数组。
edge[i]保存的就是编号为i的边信息,edge[i].to表示第i条边的终点,edge[i].next表示与第i条边同起点的下一条边的存储位置,edge[i].w为边权值。

head[]数组

head[i]表示以i为起点的第一条边存储的序号,实际上你会发现这里的第一条边存储的序号其实
就是以i为起点的所有边的最后输入的那个编号。

加边代码
//表示添了一条从u指向v的有向边,若是无向图就把u和v反过来,再添一遍
void addedge(int u,int v,int w){
	edge[++cnt_edge].nex = head[u];
	edge[cnt_edge].to = v;
	//eage[cnt_edge].w = w;
	head[u] = cnt_edge;
}

来模拟一下,以上面出现的图为例,输入边:
1 3
在这里插入图片描述因为无向图,相当于又加了一个(3,1)的有向边,下面也是一样。
在这里插入图片描述
4 3
在这里插入图片描述
在这里插入图片描述
3 6
在这里插入图片描述在这里插入图片描述
6 2
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019081722332950.png?x-oss-在这里插入图片描述

到此模拟结束。

Ⅲ.遍历

因为我们之前提到过:head[i]就是以i为起点的第一条边存储的序号,这里的第一条边存储的序号其实就是以i为起点的所有边的最后输入的那个编号。

所以使用前向星遍历的时候,我们其实是从最后一条边倒着找到所有和i相邻的边的,通过head[i]找到与i相邻的第一条边,然后按着nex的顺序一直找到nex[j] = -1,也就是没有和点i相邻的边为止。
在这里插入图片描述
就拿上边的点3,举个例子:

  • head[3] = 5,即最后一个与点3相邻的边是edge[5](3,6)。

  • edge[5].nex = 4,证明前一个和5号边同一个起始点的边是4号边(3,4),所以我们下一个访问的边就是4号边。

  • edge[4] .nex = 2,证明前一个和4号边同一个起始点的边是2号边(3,1),所以我们下一个访问的边就是2号边。

  • edge[2].nex = -1,证明2号边之前没有和2号边同起点的边了。

到此,遍历了所有与点3相邻的边。

代码

	for(int i = 1; i <= 2*m; i++){
		for(int j = head[i]; j != -1; j = edge[j].nex){
			printf("%d,%d →",i,edge[j].to);
		}
		printf(" -1\n");
//		printf("head %d : %d\n",i,head[i]);
	}

3.完整代码

#include <bits/stdc++.h>
using namespace std;
const int Max = 1e4;
struct Edge{
	int to;//第i条边的终点 
	int nex;// 表示与第i条边同起点的下一条边的存储位置
	int w;//边的权值 
}edge[Max]; 
int head[Max];
int n,m,cnt_edge=0;
void addedge(int u,int v,int w){
	edge[++cnt_edge].nex = head[u];
	edge[cnt_edge].to = v;
	//eage[cnt_edge].w = w;
	head[u] = cnt_edge;
}
int main(){
	scanf("%d %d",&n,&m);
	int tmp = m;
	memset(head,-1,sizeof(head));
	while(tmp--){
		int u,v;
		scanf("%d %d",&u,&v);
		addedge(u,v,1);
		addedge(v,u,1);
	}
	
	for(int i = 1; i <= 2*m; i++){
		printf("%d : ",i);
		for(int j = head[i]; j != -1; j = edge[j].nex){
			printf(" %d,%d →",i,edge[j].to);
		}
		printf(" -1\n");
//		printf("head %d : %d\n",i,head[i]);
	}
	return 0;
} 
/*
6 4
1 3
4 3
3 6
6 2
*/
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值