图的储存方式——边的储存

说起图的储存就先要说到变的储存了!

说起边有些童鞋恐怕还分不清楚什么和什么吧!

好,下面我们就来说一下边吧!

一。边的分类

边可以通过有无方向分为

1.有向边

2.无向边

大都数情况下我们可以把无向边看作是两条有向边

边通过有无权值分为

1.带权边

2.无权边

大多数情况下我们把无权边看作是边权为1的带权边

说完边的分类,那我们下面就要说到边的储存了!

二。边的储存

边有以下几种储存方式:

1.邻接矩阵(本人认为这是最好写的的一种了!)

   优点:实现简便,运用位运算和矩阵算法优化的时候更方便

   缺点:时空复杂度较大

2.链表储存

  优点:时空复杂度较小

  缺点:实现相对复杂

3.边集数组

  优点:容易对边进行处理 ,对边进行排序,方便整体处理

  缺点:难以对图进行遍历,难以求出每个节点相邻的边的相邻节点

 

 

邻接矩阵

对于一个给定的图,有n个点m条边,那我们若要储存这个图那就要弄一个n*m的邻接矩阵

 

注意:

 

① 在简单应用中,可直接用二维数组作为图的邻接矩阵(顶点表及顶点数等均可省略)。

 

② 当邻接矩阵中的元素仅表示相应的边是否存在时,EdgeTyPe可定义为值为0和1的枚举类型

 

③无向图的邻接矩阵是对称矩阵,对规模特大的邻接矩阵可压缩存储。

 

④邻接矩阵表示法的空间复杂度S(n)=0(n 2 )。

 

⑤建立无向网络的算法。

代码:

#include<stdio.h>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 10000
using namespace std;
int e[N][N],vis[N];
int n,m,a,b,c;
void bfs(int x)
{
    vis[x]=1;
    for(int i=1;i<=n;i++)
    {
        if(e[x][i]&&!vis[i])
         bfs(i);
    }
}
int main()
{
    scanf("%d%d",&n,&m);//n个点,m条边 
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        e[a][b]=c;//有向边 
    }
    bfs(1);
    return 0;
}

时空复杂度均为o(n^2)!

 

邻接表

对于图来说,邻接矩阵村边是一个很不错的选择!但是对于点数十分稀疏的图来说,这种方法是十分浪费空间的!!

so,我们就有了另外一种储存边的方法——邻接表!

那么你肯定会问邻接表是什么鬼,那是怎么用的??

邻接表的处理方法

1、图中顶点用一个一维数组存储,另外,对于顶点数组中,每个数据元素还需要存储指向第一个邻接点的指针,以便于查找该顶点的边信息。

2、图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以用单链表存储,无向图称为顶点vi的边表,有向图称为顶点vi作为弧尾的出边表

代码

#include<stdio.h>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 10000
#define oo 123456
using namespace std; 
int head[N],n,m,a,b,c,num;
bool vis[N];
struct Edge
{
    int next;//下一条边的编号 
    int to;//这条边到达的点 
    int dis;//这条边的长度 
}edge[N];
void ins(int from,int to,int dis)
{
        edge[++num].next=head[from];
        edge[num].to=to;
        edge[num].dis=dis;
        head[from]=num; 
}
int dfs(int x)
{
    vis[head[x]]=1;
    for(int i=1;i<=n;i++)
    {
        if(!vis[head[i]])
          dfs(i);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        ins(a,b,c);
    }
    dfs(1);
    return 0;
}

vector

 啊啊啊!这是些什么鬼!有没有感觉前面这些东西太恶心了!完全记不住啊!

好,那我们下面来弄个简单的!

stl中的vector!

vector可以看做一个不用人为开大小的一个数组,我们可以对每一个节点都使用一个vector,然后把每个节点的信息都储存在这个点的vector中即可。

对于一个有边权的图来说,有pair讲点的编号和权值结合起来储存在vector中

代码

#include<vector>
#include<cstdlib>
#include<cstring>
#include<stdio.h>
#include<iostream>
#include<algorithm>
#define N 100000
#define maxn 123456
using namespace std;
int m,n,x,y,z;
bool vis[N];
vector<pair<int,int> >vec[N];
void bfs(int x)
{
    vis[x]=1;
    for(int i=0;i<vec[x].size();i++)
    {
        if(!vis[vec[x][i].first])
          bfs(vec[x][i].first);
    }
 } 
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        vec[x].push_back(make_pair(y,z));
    }
    bfs(1);
    return 0;
 } 

 边集数组

 边集数组就是将输入的边用一个数组保存下来,而不是将其与点放在一起。

这种方法一般是在不需要点的信息时使用,不要遍历整张图,只需要每个边的信息时使用,如并查集。

当然也存在一种算法可以在使用边集数组时,十分迅速的将点的信息求出。

这种方法就是向前星。

我们可以再输入边的时候将边按照出点的顺序进行排序,这样每一个点的所有出边都是连续的。

扫一遍整张图后,我们就可以知道每一个点的所有出边所在的区间。

对于无向边我们就要存两遍!

由于要对给出的每一条边进行排序,所以时空复杂度较大。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100000
#define maxn 123456
using namespace std;
int n,m,a,b,c,len,l[N],r[N];
bool vis[N];
struct Edge
{
    int x,y,z;
}edge[N];
int cmp(Edge a,Edge b)
{
    return a.x<b.x;
}
void dfs(int x)
{
    vis[x]=1;
    for(int i=l[x];i<r[x];i++)
     if(!vis[edge[i].y])
       dfs(edge[i].y);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        edge[++len].x=a;
        edge[len].y=b;
        edge[len].z=c;
     } 
     sort(edge+1,edge+1+m,cmp);
     for(int i=1;i<=m;i++)
       if(edge[i].x!=edge[i-1].x) 
         l[edge[i].x]=r[edge[i-1].x]=i;
     dfs(1);
}

 

转载于:https://www.cnblogs.com/z360/p/6816237.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值