图 -- 邻接表实现

何为邻接表?

由于邻接矩阵存储图的方式,需要固定的开辟一块空间,比如顶点多,但是边很少,这样的邻接矩阵中存在大量的未利用空间。同时,使用数组的方式,虽然查询遍历方便,但是有时需要增删操作时,会比较麻烦且耗时。于是乎,引申出了邻接表,采用数组+单链表的方式实现链式存储。相对灵活了很多。数组存储顶点,单链表存储相应顶点相关的边集。

如何实现?

根据这样的定义,我们可以先定义头结点

data firstarc

并以头结点为基本元素定义一个数组。

接着定义表结点

adjvex nextarc

然后将顶点信息存入数组data域,或者直接下标间接表示顶点编号。如果某顶点存在关联的边,则申请一个表结点类型变量存储信息,将表结点(表示边信息)插入到对应顶点的边表中即可。这里需要考虑插入的操作如何实现,可以插在头部中间尾部,但是肯定直接插在头部,也就是头结点之后原有第一个表结点前最为方便,这样的时间复杂度为O(1)

其实顺序需要调整一下,应该先定义表结点,因为头结点的firstarc是一个指向表结点类型的指针。

开始实现

这样的数组+单链表,和哈希表有点类似,下面借用了哈希表中的描述,称数组元素为盒子。

#define MAXVEX 20	//最大顶点数

//定义边表结点
typedef struct _ArcNode
{
	int adjvex;//当前数组盒子指向顶点的位置
	struct _ArcNode * nextarc;//指向当前数组盒子下一条边的指针
}ArcNode;

//定义表头结点
typedef struct _VNode
{	
	int data;//可以利用这个data域存储某个数组盒子的边表长度以指示边数量
	ArcNode * firstarc;//指向这个盒子的第一条边
}VNode;

//定义图
typedef struct _Graph
{
	int vexnum,arcnum;//顶点数目,边数目
	VNode vexs[MAXVEX];
}Graph;

这样便完成了图的邻接表实现的相关定义。接着实现初始化的操作以及写入边信息。

//将顶点数组创建完成,并存储汇总信息
void CreateGraph(Graph * G, int vexnum, int arcnum)
{
	G->vexnum = vexnum;
	G->arcnum = arcnum;
	for (int i = 0; i < MAXVEX; ++i)
	{
		(G->vexs[i]).firstarc = NULL;
		(G->vexs[i]).data = 0;
	}
}

//定义一个边结构,方便插入操作
typedef struct _Edge
{
	int v1,v2;//v1出发点编号,v2终点编号,可依据有向或是无向具体化
	WeightType weight;//边权值,可选
}Edge;

//将边信息以边表结点的形式插入到对应的盒子
void InsertEdge(Graph * G, Edge E)
{
	//申请边表结点空间
	ArcNode * arc = (ArcNode *) malloc (sizeof(ArcNode));
	arc->adjvex = E->v2;
	arc->nextarc = NULL;

	//插入到边表中
	if((G->vexs[E->v1]).data == 0)
		(G->vexs[E->v1]).firstarc = arc;
	else{
		arc->nextarc = (G->vexs[E->v1]).firstarc;
		(G->vexs[E->v1]).firstarc = arc;
	}

	//成功插入,对应盒子的边表结点数量自增
	(G->vexs[E->v1]).data += 1;
}

总结

  1. 上述定义没有区分有向图或是无向图,在存储具体的图结构时,相应的链式结构需要做一些改变以适应相应的需求。
  2. 比如,这样的邻接表,存储无向图时,我们重复存储了同一边信息,也就是用了两个边结点表示一条边,其实是完全没必要的。针对无向图,这一点作出优化,于是产生有邻接多重表,避免重复存边信息。
  3. 存储有向图时,由于这样的表结构边表其实只是对应顶点出度的弧表,要知道对应顶点的入度,则需要遍历整个数组盒子+边表,才能确定是否存在其他顶点指向这个顶点,也就是判断入度的过程,这样是非常麻烦的。针对有向图,这一点作出优化,于是产生有十字链表,方便查询顶点入度及出度。
  4. 其实有时,这样的链式存储也未必节省了空间,在边表结点较多的情况下,比如稠密图,数组中和边表中增加的指针域与存储的信息量可比,需要V个表头结点,2E个表结点,相当于花了两倍多的空间存储。但是在稀疏图中边相对较少的情况,从节省空间的角度上来说,使用邻接表表示会较优。
发布了21 篇原创文章 · 获赞 4 · 访问量 1101

猜你喜欢

转载自blog.csdn.net/GuoningningPro/article/details/104034666