在数学上,图是表示物件与物件之间联系的数学对象;而在计算机中,每个物件可以抽象成一个节点,而关系就是一条边。

这里主要介绍图的一些较关键的性质以及邻接矩阵、邻接表的应用。

1、有向图和无向图

图分为有向图和无向图。顾名思义,有向图就是每条边都具有方向,一条从图论3——图的存储与基本性质A->图论3——图的存储与基本性质B的有向边它可以让一个东西从图论3——图的存储与基本性质A走到图论3——图的存储与基本性质B,却不能沿同一条边从图论3——图的存储与基本性质B走回图论3——图的存储与基本性质A;反之,无向图就是不具有方向的,既可以从图论3——图的存储与基本性质A图论3——图的存储与基本性质B,也可以沿同一条边从图论3——图的存储与基本性质B图论3——图的存储与基本性质A。一条边可能有一个权值,叫边权。

图论3——图的存储与基本性质图论3——图的存储与基本性质

           有向图                             无向图

注意到上面这一句话中,我强调了同一条边。这表明,一张图中可能会有重复的边,即起点和终点相同的边(在无向图中可能是起点终点位置调换的边),我们把这样的边成为重边

如果一张图中,有图论3——图的存储与基本性质n个结点,同时还有着图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质n−1条边,那么这张图事实上是一颗树。

如果这张图中,从图论3——图的存储与基本性质A一直沿着某些不重复的边走,然后能走回图论3——图的存储与基本性质A,那么这张图中就存在着环。一张图中可能存在着很多个环,也可能一个都没有。例如,在上面的有向图中,不存在环,而在无向图中,结点图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质2,4,7构成了一个环。

2、图的存储

限于篇幅,这里仅介绍最常用的邻接矩阵和邻接表

2.1 邻接矩阵法

 我们可以构造一个矩阵,矩阵的第图论3——图的存储与基本性质i行第图论3——图的存储与基本性质j列(即图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质gi,j)表示结点图论3——图的存储与基本性质i和结点图论3——图的存储与基本性质j的关系,而没有连边的两个节点,我们就设置为“假想无穷大”。例如,上面的有向图可以表示为(inf即“假想无穷大”):

图论3——图的存储与基本性质

这里为第图论3——图的存储与基本性质i行第图论3——图的存储与基本性质j列为1表示有连边。大家可以自行验证是否表示上述有向图。用代码表示就可以是 g[i][j]=1; .无向图也可以类似的表示,注意,因为边是无向的,所以一旦第图论3——图的存储与基本性质i行第图论3——图的存储与基本性质j列有连边,那么第图论3——图的存储与基本性质j行第图论3——图的存储与基本性质i列也一定是有连边的。用代码表示即为 g[i][j]=g[j][i]=1; 。那么邻接矩阵法就讲完了。可是,如果对于这样一个数据范围:

对于图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质100%的数据满足图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质图论3——图的存储与基本性质n≤106,m≤106,其中图论3——图的存储与基本性质n表示节点数,图论3——图的存储与基本性质m表示边数。

如果空间限制是标准的256MB或512MB,即使是1GB,存邻接矩阵也是不够的啊!邻接矩阵的二维数组的空间消耗是O(图论3——图的存储与基本性质图论3——图的存储与基本性质n2)的。注意到有很多无用的空间,也就是上面的inf,事实上比我们有用的空间还多(在浏览上面的表格时你有没有这么想呢?)。因为边的数量较小,于是我们考虑,能不能主要存边的信息,而尽量不存点呢?于是我们的邻接表就出来了。

2.2 邻接表法

邻接表的思想就是存边的信息,而不是点的信息。我们给每一条边一个编号。
图论3——图的存储与基本性质

仍然对于上面的有向图,我们邻接表里存的内容可以这么表示:(其中冒号前的数字表示表示这一条边的编号)

图论3——图的存储与基本性质

邻接表存的就是这么一个东西。它首先每个节点都有存一个“从这条边出发的第一条边”,然后每一条边除了保存自身的信息(包括到哪里去,权值等)以外,还有指向下一条边的编号。这让我们想起了什么?对,链表!它每个节点内存的内容就很像链表,然后下一条边指向0就表示结束了,这个节点的边就遍历忘了。这样也是可以存储一个图的。这种方法的优点就是空间复杂度上的优势,它的空间复杂度(如果不考虑每个节点存的“第一条边”的话)是O(图论3——图的存储与基本性质m)的。那么对于上面的数据范围就可以很轻松的解决了。

可是这种方法也有缺点,例如判断点之间是否联通,那么查找最坏情况下要O(图论3——图的存储与基本性质m)的复杂度,而邻接矩阵只需要O(图论3——图的存储与基本性质1)。

接下来给出两种存图方法的Cpp代码:

图论3——图的存储与基本性质
#include<cstdio>
#include<cstring>
//邻接矩阵
const int MAXN=3010;
int g[MAXN][MAXN];//graph
int n,m;

//在一般情况下,u和v分别表示边的起点和终点,w表示权值
void init()
{
    memset(g,0x7f,sizeof(g));//inf
    for(int i=1;i<=n;i++)
        g[i][i]=0;
}
void adde(int u,int v,int w)
{
    g[u][v]=w;//有向
    g[u][v]=g[v][u]=w;//无向
}
图论3——图的存储与基本性质
图论3——图的存储与基本性质
#include<cstdio>
#include<cstring>
//邻接表
const int MAXN=100010;
const int MAXM=200010;//注意,无向图空间双倍!

struct edge
{
    int to,w,nxt;
}e[MAXM];
int fir[MAXN];
int n,m,tot=0;

void adde(int u,int v,int w)
{
    e[++tot].to=v;e[tot].w=w;
    e[tot].nxt=fir[u];
    fir[u]=tot;
}
图论3——图的存储与基本性质

打一个广告,我自己的博客中还有使用邻接表储存的堆优化Dijkstra算法,有兴趣的同学可以浏览一下。限于水平,作者所写的难免有疏忽之处,望大家指正,Thank

相关文章:

  • 2021-07-20
  • 2021-08-25
  • 2022-12-23
  • 2021-06-27
  • 2021-09-26
  • 2022-02-01
猜你喜欢
  • 2022-12-23
  • 2021-05-25
  • 2021-07-19
  • 2022-12-23
  • 2022-12-23
  • 2021-12-29
  • 2022-01-15
相关资源
相似解决方案