图的存储方式

· · 个人记录

本文主要介绍图的几种存储方式。

先掏出一张图,设上图有 n 个点、m 条边。

那么怎么存储它呢?下面介绍三种常用方式。

邻接矩阵

构建 a 数组,其中 a[i][j] 表示是否能从点 i 到点 j 。

如: a[1][2]=1

代码:

int n,m,x,y;
int a[1005][1005];
cin>>n>>m;
for(int i=1; i<=m;i++)
{
    cin>>x>>y;
    a[x][y]=1;
    //需要注意的是,对于无向图还需反向建边一次 
}

空间复杂度 n^2

二维 vector

可以理解为邻接矩阵的优化版,用到了动态数组。

有两维,第一维代表点,第二维代表该点连接的点。

代码:

int n,m,x,y;
vector<int>v[1005];
cin>>n>>m;
for(int i=1; i<=m;i++)
{
    cin>>x>>y;
    v[x].push_back(y); 
}
for(int i=1; i<=n;i++)
 for(int j=0; j<v[i].size();j++) 
 {
    cout<<i<<"->"<<v[i][j]<<endl;
 }

空间复杂度 nm

链式前向星

需要定义结构体 edge 数组。

每个元素包含:下一个与该边同起点的边序号、终点、边权等。

struct e
{
   int next; //下一条边 
   int w; //边权 
   int v; //终点 
}edge[100005];

我们再引入一个数组 head ,表示以 u 为起点所指向的一条边。

这样就可以完成加边操作了。

void add(int u,int v,int w)
{
    //cnt代表当前有几条边
    edge[++cnt].w=w;
    edge[cnt].v=v;
    edge[cnt].next=head[u]; //将下一条边指向头 
    head[u]=cnt; //将头设为这条边 
}

最后是遍历,由一点延伸出的边:

for(int i=head[u]; i;i=edge[i].next)
{
    cout<<u<<"->"<<edge[i].v<<endl;
} 

空间复杂度 m

总结

几种方式都有各自优劣,邻接矩阵在稠密图中效率高,链式前向星在稀疏图中占优。

最后,这几种方法都是很重要的基础,要多熟悉熟悉它们。