7.4 图的存储结构
图是无法以数据元素在内存中的物理位置来表示元素之间的关系,下面提供5种图的不同的存储结构。
7.4.1邻接矩阵(又叫数组表示法)
考虑到图由定点和边或弧组成,和在一起比较困难,那就很自然的考虑分两个结构来分别存储。顶点不分大小、主次,所以用一个一维数组来存储是不错的选择。而边或弧由于是顶点与顶点之间的关系,一维搞不定,那就考虑用一个二维数组来存储。于是我们的邻接矩阵的方案诞生了。
图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(称为邻接矩阵)存储图中的边或弧的信息。
设图G(V,E)有n个顶点,则邻接矩阵是一个n x n 的方阵,定义为:
无向图的边数组是一个对称矩阵。
(1)要判定任意两顶点是否有边无边就容易了,只需看边数组中arc[i][j]是否等于1。
(2)要知道某个顶点的度,其实就是这个顶点Vi在邻接矩阵第i行的元素之和。
(3)求顶点Vi的所有邻接点,就是将邻接矩阵中第i行元素扫描一遍,arc[i][j]为1就是邻接点。
我们再来看一个有向图样例
有向图讲究入度和出度。顶点V1的入度就是第1列各个元素之和。顶点V1的出度就是第1行各个元素之和。
邻接矩阵的存储结构
#define MAXVEX 100
#define INFINITY 65535
typedef struct
{
char vexs[MAXVEX]; //顶点表,存储顶点
int arc[MAXVEX] [MAXVEX]; //邻接矩阵,存储边的信息
int numVertexes; //图中的顶点的数目
int numEdges;//图中的边的数目
}MGraph;
7.4.2邻接表
邻接矩阵,对于变数相对较少的图,这种结构存在对存储空间的极大浪费。现在考虑另外一种存储方式,邻接表。
1、图中的顶点用一个一维数组存储,当然,顶点可以用单链表来存储,不过数组更容易读取顶点信息,更加方便。另外,对于顶点数组中,每个元素还需要存储指向第一个邻接点的指针,以便查找该顶点的边信息。
2、图中每个顶点Vi的所有邻接点构成一个线性表,由于邻接点个数不定,所以采用单链表存储,无向图称为顶点Vi的边表,有向图则称为Vi作为弧尾的出边表。
对于这样的结构:
(1)要想知道某个顶点的度,就去查找这个顶点的边表中节点的个数。
(2)若要判断顶点Vi到Vj是否存在边,只需要测试顶点Vi的边表中adjvex是否存在节点Vj的下标j就行了。
(3)若求顶点的所有邻接点,其实就是对此顶点的边表进行遍历,得到的adjvex域对应的顶点就是邻接点。
若是有向图,我们以顶点为弧尾来存储边表的,这样很容易得到每个顶点的出度,但有时为了便于确定顶点的入度或以顶点为弧头的弧,我们可以建立一个有向图的逆邻接表。如下图所示:
对于带权值的,可以在边表节点定义中再增加一个weight的数据域,存储权值信息即可
7.4.3十字链表
对于有向图,邻接表关心了出度,想了解入度就必须要遍历整个图才能知道,有没有可以把邻接表和逆邻接表结合起来呢,就是十字链表。
7.4.4邻接多重表
7.4.5边集数组