数据结构与算法十一:2.2 图的存储结构---邻接表

659 阅读4分钟

这是我参与8月更文挑战的第24天,活动详情查看:8月更文挑战

关注我,以下内容持续更新

数据结构与算法(一):时间复杂度和空间复杂度

数据结构与算法(二):桟

数据结构与算法(三):队列

数据结构与算法(四):单链表

数据结构与算法(五):双向链表

数据结构与算法(六):哈希表

数据结构与算法(七):树

数据结构与算法(八):排序算法

数据结构与算法(九):经典算法面试题

数据结构与算法(十):递归

数据结构与算法(十一):图


上一篇文章介绍了图的存储方式:邻接矩阵表示法,本篇继续介绍图的另外一种存储方式--邻接表.

前言

在介绍邻接表之前,先思考下两个问题
① 图的邻接矩阵存储结构的空间复杂度是多少?
假设图G有n个顶点e条边,则存储该图的时间复杂度是O(n²)。
② 如果用邻接矩阵存储稀疏图会出现什么现象?
当一个图为稀疏图时,同样需要n²的空间,势必会造成空间的浪费。那么我们今天学的邻接表就是适用于稀疏图的一种存储方式。

图的存储结构--邻接表

1. 邻接表存储的基本思想
对于图的每个顶点vi,将所有邻接于vi的顶点链成一个单链表,称为顶点vi的边表(对于有向图则称为出边表),所有边表的头指针和存储顶点信息的一维数组构成了顶点表。

2. 邻接表的结构
邻接表由顶点表结点VertexNode和边表结点EdgeNode两种结点构成。

  • 顶点表结点由data和firstEdge构成。
    • data:数据域,存放顶点信息。
    • firstEdge:指针域,指向边表中第一个结点。
  • 边表结点由adjvex和next构成。
    • adjvex:邻接点域,边的终点在顶点表中的下标。
    • next:指针域,指向边表中的下一个结点。
    • weight; 用于存储权值,对于非网图可以不需要

3.1 无向图的邻接表 image.png

(1)无向图的邻接表
- 顶点i的度:顶点i的边表中结点的个数; - 如何判断顶点i和顶点j之间是否存在边:查找顶点 i 的边表中是否存在终点为 j 的结点 **3.2 有向图的邻接表**

image.png

(2)有向图的邻接表
- 求顶点i的出度:顶点i的出边表中结点的个数; - 求顶点i的入度:各顶点的出边表中以顶点i为结点的结点个数 - 求顶点i的所有邻接点:遍历顶点i的边表,该边表中的所有顶点都是顶点i的邻接点 **3.3 网图的邻接表**

image.png

(2)网图的邻接表

4. 邻接表存储网图的代码

#define MAXVEX 100 /* 最大顶点数,应由用户定义 */
 
//边表结点
typedef struct EdgeNode
{
    int adjvex; //邻接点域,存储该顶点对应的下标
    int weight; //用于存储权值,对于非网图可以不需要
    struct EdgeNode *next;  //链域,指向下一个邻接点
}EdgeNode;

//顶点表结点
typedef struct VertexNode 
{
    char data; //顶点域,存储顶点信息
    EdgeNode *firstedge; //边表头指针
}VertexNode,AdjList[MAXVEX];

//图的邻接表存储方式
typedef struct
{
    AdjList adjList;
    int n,e;//图中当前顶点数和边数
}GraphAdjList;

/* 建立图的邻接表结构 */
void  CreateALGraph(GraphAdjList *G)
{
	int i,j,k;
	EdgeNode *e;
	printf("输入顶点数和边数:\n");
	scanf("%d,%d",&G->n,&G->e); /* 输入顶点数和边数 */
	for(i = 0;i < G->n;i++) /* 读入顶点信息,建立顶点表 */
	{
		scanf(&G->adjList[i].data); 	/* 输入顶点信息 */
		G->adjList[i].firstedge=NULL; 	/* 将边表置为空表 */
	}
	
	
	for(k = 0;k < G->e;k++)/* 建立边表 */
	{
		printf("输入边(vi,vj)上的顶点序号:\n");
		scanf("%d,%d",&i,&j); /* 输入边(vi,vj)上的顶点序号 */
		e=(EdgeNode *)malloc(sizeof(EdgeNode)); /* 向内存申请空间,生成边表结点 */
		e->adjvex=j;					/* 邻接序号为j */                         
		e->next=G->adjList[i].firstedge;	/* 将e的指针指向当前顶点上指向的结点 */
		G->adjList[i].firstedge=e;		/* 将当前顶点的指针指向e */               
		
		e=(EdgeNode *)malloc(sizeof(EdgeNode)); /* 向内存申请空间,生成边表结点 */
		e->adjvex=i;					/* 邻接序号为i */                         
		e->next=G->adjList[j].firstedge;	/* 将e的指针指向当前顶点上指向的结点 */
		G->adjList[j].firstedge=e;		/* 将当前顶点的指针指向e */               
	}
}

5. 时间复杂度
邻接表的空间复杂度为O(n+e),那么空间复杂度是如何计算的呢?在无向图的邻接表中,顶点表有n个元素,边表中有2e个边表结点,所以空间占据了n+2e,时间复杂度表示为O(n+e)。

邻接矩阵和邻接表的比较

image.png

关注我

如果觉得我写的不错,请点个赞 关注我 您的支持是我更文最大的动力!