图的存储及基本操作
1 邻接矩阵
所谓邻接矩阵存储结构,就是用一维数组存储图中顶点的信息,用矩阵表示图中各顶点之间的邻接关系。
0 或∞ 若(v i ,v j )或<v i ,v j >不是 E(G)中的边
其中,w ij 表示边(v i ,v j )或<v i ,v j >上的权值;∞表示一个计算机允许的、大于所有边上权值的数。
从图的邻接矩阵存储方法容易看出,这种表示具有以下特点:
(1)无向图的邻接矩阵一定是一个对称矩阵。因此,在具体存放邻接矩阵时只需存放上(或下)三角矩阵的元素即可。
(2)对于无向图,邻接矩阵的第 i 行(或第 i 列)非零元素(或非∞元素)的个数正好是第 i 个顶点的度 TD(v i )。
(3)对于有向图,邻接矩阵的第 i 行(或第 i 列)非零元素(或非∞元素)的个数正好是第 i 个顶点的出度 OD(v i )(或入度 ID(v i ))。
(4)用邻接矩阵方法存储图,很容易确定图中任意两个顶点之间是否有边相连;但是,
要确定图中有多少条边,则必须按行、按列对每个元素进行检测,所花费的时间代价很大,这是用邻接矩阵存储图的局限性。
在用邻接矩阵存储图时,除了用一个二维数组存储用于表示顶点间相邻关系的邻接矩阵外,还需用一个一维数组来存储顶点信息,另外还有图的顶点数和边数。故可将其形式描述如下:
4.2.2 邻接表
邻接表(Adjacency List)是图的一种顺序存储与链式存储结合的存储方法。邻接表表示法类似于树的孩子链表表示法。就是对于图 G 中的每个顶点 v i ,将所有邻接于 v i 的顶点 v j 链成一个单链表,这个单链表就称为顶点 v i 的邻接表,再将所有点的邻接表表头放到数组中,就构成了图的邻接表。在邻接表表示中有两种结点结构,如图所示。
邻接矩阵表示的结点结构
一种是顶点表的结点结构,它由顶点域(data)和指向第一条邻接边的指针域(firstarc)构成,另一种是边表(即邻接表)结点,它由邻接点域(adjvex)和指向下一条邻接边的指针域(nextarc)构成。对于网图的边表需再增设一个存储边上信息(如权值等)的域(info)。
邻接表表示的形式描述如下:
(1)若无向图中有 n 个顶点、e 条边,则它的邻接表需 n 个头结点和 2e 个表结点。显然,在边稀疏(e<<n(n-1)/2)的情况下,用邻接表表示图比邻接矩阵节省存储空间,当和边相关的信息较多时更是如此。
(2)在无向图的邻接表中,顶点 v i 的度恰为第 i 个链表中的结点数.
(3)而在有向图中,第 i 个链表中的结点个数只是顶点 v i 的出度,为求入度,必须遍历整个邻接表。在所有链表中其邻接点域的值为 i 的结点的个数是顶点 v i 的入度。有时,为了便于确定顶点的入度或以顶点 v i 为头的弧,可以建立一个有向图的逆邻接表,
即对每个顶点 v i 建立一个链接以 v i 为头的弧的链表。
在建立邻接表或逆邻接表时,若输入的顶点信息即为顶点的编号,则建立邻接表的复杂度为 O(n+e),否则,需要通过查找才能得到顶点在图中位置,则时间复杂度为 O(n·e)。
(4)在邻接表上容易找到任一顶点的第一个邻接点和下一个邻接点,但要判定任意两个顶点(v i 和 v j )之间是否有边或弧相连,则需搜索第 i 个或第 j 个链表,因此,不及邻接矩阵方便。
1 邻接矩阵
所谓邻接矩阵存储结构,就是用一维数组存储图中顶点的信息,用矩阵表示图中各顶点之间的邻接关系。
假设图 G=(V,E)有 n 个确定的顶点,即 V={v 0 ,v 1 ,…,v n-1 },则表示 G 中各顶点相邻关系为一个 n×n 的矩阵,矩阵的元素为:A[i][j]= 1 若(v i ,v j )或<v i ,v j >是 E(G)中的边
0 若(v i ,v j )或<v i ,v j >不是E(G)中的边
若 G 是网图,则邻接矩阵可定义为:
A[i][j]= w ij 若(v i ,v j )或<v i ,v j >是 E(G)中的边0 或∞ 若(v i ,v j )或<v i ,v j >不是 E(G)中的边
其中,w ij 表示边(v i ,v j )或<v i ,v j >上的权值;∞表示一个计算机允许的、大于所有边上权值的数。
从图的邻接矩阵存储方法容易看出,这种表示具有以下特点:
(1)无向图的邻接矩阵一定是一个对称矩阵。因此,在具体存放邻接矩阵时只需存放上(或下)三角矩阵的元素即可。
(2)对于无向图,邻接矩阵的第 i 行(或第 i 列)非零元素(或非∞元素)的个数正好是第 i 个顶点的度 TD(v i )。
(3)对于有向图,邻接矩阵的第 i 行(或第 i 列)非零元素(或非∞元素)的个数正好是第 i 个顶点的出度 OD(v i )(或入度 ID(v i ))。
(4)用邻接矩阵方法存储图,很容易确定图中任意两个顶点之间是否有边相连;但是,
要确定图中有多少条边,则必须按行、按列对每个元素进行检测,所花费的时间代价很大,这是用邻接矩阵存储图的局限性。
在用邻接矩阵存储图时,除了用一个二维数组存储用于表示顶点间相邻关系的邻接矩阵外,还需用一个一维数组来存储顶点信息,另外还有图的顶点数和边数。故可将其形式描述如下:
#define MAX_VERTEX_NUM 20 //最大顶点数设为 20
typedef char VertexType; //顶点类型设为字符型
typedef int VRType; //边的权值设为整型
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; //顶点表
VRType edges[MAX_VERTEX_NUM][ MAX_VERTEX_NUM]; //邻接矩阵,即边表
int vexnum,arcnum; //顶点数和边数
}MGragh; //MGragh 是邻接矩阵存储的图类型
4.2.2 邻接表
邻接表(Adjacency List)是图的一种顺序存储与链式存储结合的存储方法。邻接表表示法类似于树的孩子链表表示法。就是对于图 G 中的每个顶点 v i ,将所有邻接于 v i 的顶点 v j 链成一个单链表,这个单链表就称为顶点 v i 的邻接表,再将所有点的邻接表表头放到数组中,就构成了图的邻接表。在邻接表表示中有两种结点结构,如图所示。
顶点域 边表头指针 邻接点域 指针域
data firstarc adjvex nextarc
顶点表 边表邻接矩阵表示的结点结构
一种是顶点表的结点结构,它由顶点域(data)和指向第一条邻接边的指针域(firstarc)构成,另一种是边表(即邻接表)结点,它由邻接点域(adjvex)和指向下一条邻接边的指针域(nextarc)构成。对于网图的边表需再增设一个存储边上信息(如权值等)的域(info)。
邻接表表示的形式描述如下:
#define MAX_VERTEX_NUM 20 //最大顶点数为 20
typedef struct ArcNode{ //边表结点
int adjvex; //邻接点域
struct ArcNode *nextarc; //指向下一个邻接点的指针域
//若要表示边上信息,则应增加一个数据域 info
}ArcNode;
typedef struct VNode{ //顶点表结点
VertexType data; //顶点域
ArcNode *firstarc; //边表头指针
}VNode, AdjList[MAX_VERTEX_NUM]; //AdjList 是邻接表类型
typedef struct{
data firstarc adjvex nextarc
AdjList adjlist; //邻接表
int vexnum,arcnum; //顶点数和边数
}ALGraph; //ALGraph 是以邻接表方式存储的图类型
从图的邻接表存储方法容易看出,这种表示具有以下特点:
(1)若无向图中有 n 个顶点、e 条边,则它的邻接表需 n 个头结点和 2e 个表结点。显然,在边稀疏(e<<n(n-1)/2)的情况下,用邻接表表示图比邻接矩阵节省存储空间,当和边相关的信息较多时更是如此。
(2)在无向图的邻接表中,顶点 v i 的度恰为第 i 个链表中的结点数.
(3)而在有向图中,第 i 个链表中的结点个数只是顶点 v i 的出度,为求入度,必须遍历整个邻接表。在所有链表中其邻接点域的值为 i 的结点的个数是顶点 v i 的入度。有时,为了便于确定顶点的入度或以顶点 v i 为头的弧,可以建立一个有向图的逆邻接表,
即对每个顶点 v i 建立一个链接以 v i 为头的弧的链表。
在建立邻接表或逆邻接表时,若输入的顶点信息即为顶点的编号,则建立邻接表的复杂度为 O(n+e),否则,需要通过查找才能得到顶点在图中位置,则时间复杂度为 O(n·e)。
(4)在邻接表上容易找到任一顶点的第一个邻接点和下一个邻接点,但要判定任意两个顶点(v i 和 v j )之间是否有边或弧相连,则需搜索第 i 个或第 j 个链表,因此,不及邻接矩阵方便。