【OI结构】邻接表与邻接矩阵

来源:互联网 发布:csgo 服务器优化 编辑:程序博客网 时间:2024/06/10 23:51

引子

如果我给出一个图,图中有几个点,我现在给出点之间的连接关系,我们如何存储呢?

邻接矩阵

我们开一个数组a[N][N],a[i][j]表示i到j可以连接,连接的距离是多少。

优点:访问特别快,判断i到j是否可以连接。时间复杂度O(1)。我们在用floyd(多源最短路)时,也需要用到这种存储方式。

缺点:空间复杂度O(N*N)N是点的数量,当N在10000以上的时候,就不能使用领接矩阵。

解决方法:我们发现在数组中,很多地方是没有用到的。我们应该“物尽其用”~


领接表

我们不把点作为存储方式。而将边作为存储方式呢?我们用一个结构体存储边的信息。包括它的编号、起点、终点、权值。

struct qq{int x,y,d;}a[100005];

这种情况下,空间复杂度是O(M),M为边数,时间复杂度也是O(M),比较慢。

所以我们用下面的结构优化:

在结构体中再加入一个标记:next,表示相同起点的接下来的边。(“接下来的”这一个概念当然是自己作出来的)

然后建立一个first数组,first[i]表示下一条起点为i的边,对于它来说的“接下来的边”是谁。

刚开始first数组初始化为0

当我们读入一条边的时候,它的next是它起点的first,它起点的first变成它的编号。

举个例子:在下面的图中:


我加入一条(3,4)的边:让它的next指向first[3](也就是0),然后first[3]=编号(本图中是4)

加入(2,4)的边:让它的next指向first[2](也就是(2,3)的编号),然后让first[2]=编号(本图中是5)


邻接表的建立方法:

void make_l(int x,int y,int d){len++;//编号a[len].x=x;a[len].y=y;a[len].d=d;a[len].next=first[x];first[x]=len; }

而领接表的访问,最坏情况是O(M),但是会比这个快很多(重点)

for(int i=first[x];i!=0;i=a[i].next)

从所有起点为x的边的first开始。因为一开始first初始化为0,所以终止条件为i!=0,然后访问它的下一条边。

1 0