浅谈图论-1.1图的几种存储方式以及连通

前言


图,不是可以三言两语说得通的数据结构,比如树严格来说也是一种图,如果树中带环,就变成了图。

正文

如果不知道本节的重点,请先阅读标题。接下来我们直接开始。

首先,图你可以通俗的理解为几座城市,比如ABCD四座,A和B之间有城际公路,B和C有城际公路,D没有往外的城际公路,那么只要是个酱紫就知道A可以去B去C,B可以去A去C,C可以去A去B,D无处可去。在图中,我们把“城际高速”称为边,城市称作点或结点,而像D这样的城市叫“孤点”或“孤岛”。很通俗易懂,对吧?
然后是单向图与无向图,仍然通过举例来说明。
假设A点和B点连通,
但只能从A点去B点,这就是单向连通;
如果A点可以去B点,B点也可以去A点,这就是双向连通。


那么你可能会说,这样讲图不就是个数学模型嘛?编程上不是什么用也没有吗?那么我们现在引入两个概念,及出度and入度。你可以这么想,一个结点可以直接去到的结点的个数(不可以绕路)叫做出度,而可以直接去到该结点的结点个数(不可以绕路)叫做入度。


还是很简单的道理,有了以上概念,还是要进入代码环节。如何存储图呢?(提前预告一下,关于图的其他知识,比如图的搜索、洪水填充、完全图等知识会在下一节提到)


关于存储图的方法,可谓是群英集萃,目前作者已知的有4种,邻接矩阵、邻接点列表以及结构体数组和链式前向星。下文会分开赘述。


邻接矩阵

顾名思义,邻接矩阵就是把图的结点的连通关系保存在一个矩阵中。
优点很明显,就是可以很清楚地知道A点与B点是否连通。
但缺点也很多,比如空间的限制,假设我现在有10000个结点,a[10001][10001] 这么大的数组是开不出来的。
接下来演示邻接矩阵的存储方法。

#define MAXN 1008
bool a[MAXN][MAXN];
int n,m,nodex,nodey;
cin>>n>>m; // 有n个点,m个邻接关系
for(int i=1;i<=n;i++){
	cin>>nodex>>nodey;
	a[nodex][nodey]=1; 
	// a[nodey][nodex]=1; 这一句只有双向连通时使用
}

我相信这应该是图最简单的存储方式了。

邻接点列表

作者本人也是十分喜欢这种存储方式的。
优点是可以罗列出每一个点的所有直接连通点。
缺点也很明显,空间仍然可以hack该方法。

vector<vector<int> > aplist(1001);
int a,b;
cin>>a>>b;
aplist[a].push_back(b);
aplist[b].push_back(a); // 如果是单向连通这句就不要了

因为一个点可能有许多直接连接点,所以vector还是很不错的选择。

结构体数组

应该是最LJ的图存储方式了,通常用struct或pair实现,这里演示struct。
优点:好像莫得
缺点:不可以直接明了的表示结点与结点的连通关系,甚至不如静态数组?

const int MAXN=1008;
struct node{
	int x,y;
}a[MAXN];
int n;
cin>>n;
for(int i=1;i<=n;i++){
	cin>>a[i].x>>a[i].y;
}

链式前向星

听名字就知道贼高端,但是需要先掌握链表的知识,接下来仅展示一个模板

#include 
using namespace std;
struct node{
	int v;
	int w;
	int next;  //下一条边的编号
};
int head[10001];// 头,出
node edge[1000000]; // 第i条边
int cnt;
void add(int x,int y,int z){
	edge[cnt].v=y;
	edge[cnt].w=z;
	edge[cnt].next=head[x];
	head[x]=cnt++;
	return ;
}
int main (){
	memset(head,-1,sizeof(head));
	int n,m;
	cin>>n>>m;
	int i;
	for(i=1;i<=m;i++){
		int u,v,w;
		add(u,v,w);
		add(v,u,w);//无向图才要写
	}
	//遍历节点1的所有出边
	for(i=head[1];~i;i=edge[i].next){
		// 呱啦呱啦
	}
	return 0;
}

其实还是比较简单的啦。


以上就是图的所有存储方式啦!如果你觉得这篇blog还不错的话可以点个免费的赞嘛QwQ?

你可能感兴趣的:(浅谈数据结构及算法,图论,算法,数据结构,c++)