文章目录
Storage
1.邻接矩阵法
1.1 Definition
即:
- 用一个一维数组存储图的顶点信息
- 用一个二维数组存储图的边的信息(即顶点和顶点之间的邻接关系),这个矩阵就是邻接矩阵
对于一个结点数目为
n
n
n 的图
G
(
V
,
E
)
G(V,E)
G(V,E) 的邻接矩阵
A
A
A 是一个
n
×
n
n\times n
n×n 的矩阵:
A
[
i
]
[
j
]
=
{
1
,
若
(
v
i
,
v
j
)
或
<
v
i
,
v
j
>
是
E
(
G
)
中
的
边
0
,
反
之
A[i][j]=\begin{cases} 1,&若(v_{i},v_{j})或<v_{i}, v_{j}>是E(G)中的边\\ 0,&反之 \end{cases}
A[i][j]={1,0,若(vi,vj)或<vi,vj>是E(G)中的边反之
其中,
v
i
,
v
j
v_{i},v_{j}
vi,vj 是图中的任意两个顶点,
(
v
i
,
v
j
)
(v_{i}, v_{j})
(vi,vj) 对应无向图中包含这两个顶点的边,
<
v
i
,
v
j
>
<v_{i},v_{j}>
<vi,vj> 对应于有向图中包含这两个顶点的边。
对于带权图来说:
A
[
i
]
[
j
]
=
{
w
i
,
j
,
若
(
v
i
,
v
j
)
或
<
v
i
,
v
j
>
是
E
(
G
)
中
的
边
0
或
∞
,
反
之
A[i][j]=\begin{cases} w_{i,j},&若(v_{i},v_{j})或<v_{i}, v_{j}>是E(G)中的边\\ 0或\infin,&反之 \end{cases}
A[i][j]={wi,j,0或∞,若(vi,vj)或<vi,vj>是E(G)中的边反之
即相连的顶点之间用权重表示,用
0
,
∞
0,\infin
0,∞ 表示不相邻的顶点,则我们图的定义如下:
#define MAX_VERTEX 100
typedef struct Graph{
int vertices[MAX_VERTEX];
int edges[MAX_VERTEX][MAX_VERTEX];
int vnum = 0;
int enum = 0;
}Graph;
1.2 Characteristic
邻接矩阵法的特点:
- 无向图的邻接矩阵一定是一个对称矩阵(并且唯一),只需存储上三角或下三角矩阵即可
- 对于无向图,邻接矩阵第 i i i 行或者第 i i i 列的非零元素的个数即为这第 i i i 个顶点的度
- 对于有向图,邻接矩阵的行列中的非零元素的个数分别是该顶点的出度和入度(具体对应关系取决于矩阵的定义)
- 容易确定两点之间的相关性,但不易确定图中边数
- 适合表示稠密图(非零元素较多)
- 邻接矩阵 A A A, A n A^{n} An 中的非零元素表示从一个顶点到另外一个顶点存在长度为 n n n 的路径
2.邻接表法
2.1 Definition
邻接表法可以用于解决邻接矩阵法在存储稀疏矩阵的时候存储空间大量浪费的问题,结合了顺序存储和链式存储的方法,首先,对所有顶点建立一个单链表:
data | firstarc |
---|
其中,data
为顶点域,firstarc
为边表的头指针,即包含这个顶点的所有边中除了这个顶点外的另外顶点的链表,对于有向图来说,这个链表是一个出边表,存储的是这个顶点的出边的所有边头,边表的结点如下:
data | nextarc |
---|
nextarc
,指向下一个该顶点的邻接顶点,即下一条边,存储结构定义如下:
#define MAX_VEX 100
class Graph{
public:
// 边表
typedef struct ArcNode{
int adjv;
ArcNode *next;
}ArcNode;
// 顶点表
typedef struct VexNode{
int v;
ArcNode* first;
}VexNode;
private:
VexNode vexList[MAX_VEX];
int vexNum, arcNum;
public:
// operations
};
2.2 Characteristic
邻接表法具有以下特点:
- 无向图:存储空间为 O ( ∣ V ∣ + 2 ∣ E ∣ ) O(|V|+2|E|) O(∣V∣+2∣E∣),因为每条边需要在两个顶点的边表中都出现,有向图:存储空间为 O ( ∣ V ∣ + ∣ E ∣ ) O(|V|+|E|) O(∣V∣+∣E∣),出边在每个顶点对应的边表中是唯一的
- 存储稀疏图时可以节省大量空间
- 容易找出顶点的所有邻边;不易确定两点是否邻接(相对于邻接矩阵法)
- 易求出度,难求入度(需遍历整表),而在邻接矩阵法中都可以在 O ( n ) O(n) O(n) 的时间内求得
- 邻接表不唯一,在于边表中边的次序没有规定
3.十字链表
3.1 Definition
有向图的一种链式存储方式。十字链表中,有向图每一个顶点都有一个结点:
data | firstin | firstout |
---|
其中:
data
:结点数据firstin
:指向这个顶点的第一条入边对应的弧结点firstout
:指向这个顶点的第一条出边对应的弧结点- 需要注意的是,所有顶点是按顶点序号顺序存储的
每一条弧也有一个结点:
tail | head | headlink | taillink | info |
---|
其中:
tail
:弧尾顶点head
:弧头顶点headlink
:下一个弧尾相同的弧结点taillink
:下一个弧头相同的弧结点info
:弧的相关信息如权重等
存储结构定义如下:
#define MAX_VEX 100
class Graph{
public:
// 弧结构
typedef struct ArcNode{
int tail;
int head;
ArcNode* headlink;
ArcNode* taillink;
// info
}ArcNode;
// 顶点结构
typedef struct VexNode{
// data
ArcNode* firstout;
ArcNode* firstin;
};
private:
VexNode vexList[MAX_VEX];
int vexNum, arcNum;
public:
// operations
};
3.2 Characteristic
十字链表的特点:
- 既易找到顶点入边,也易找到顶点出边
- 唯一确定一个图,但是图十字链表不唯一
4.邻接多重表
无向图的一种链式存储方式,解决邻接表法中难求顶点之间是否邻接的问题。同样,每条边也由一个结点表示:
mark | ivex | ilink | jvex | jlink | info |
---|
其中:
mark
:标志域,标记是否被搜索过ivex
:对应表头的顶点ilink
:指向表头的顶点相关的下一条弧jvex
:表头顶点的邻接顶点,即这条弧的另外一个顶点jlink
:指向和这个邻接顶点相关的下一条弧
每个顶点也由一个结点表示:
data | firstedge |
---|
存储结构定义如下:
#define MAX_VEX
class Graph{
public:
// 边表结点
typedef struct ArcNode{
bool mark;
int ivex;
int jvex;
ArcNode* ilink;
ArcNode* jlink;
// info
}ArcNode;
// 顶点表结点
typedef struct VexNode{
// data
ArcNode* firstEdge;
}VexNode;
private:
VexNode vexList[MAX_VEX];
int vexNum, arcNum;
public:
// operations
};
Basic Operation
常见的操作如下:
Adjacent(v1, v2) - bool
:判断两个顶点是否邻接Neighbors(v) - VexNode[]
:返回这个所给顶点的所有邻接顶点InsertVertex(data) - void
:插入一个顶点DeleteVertex(v) - void
:删除一个顶点AddEdge(v1, v2, info) - void
:加入一条边RemoveEdge(v1, v2) - void
:移除一条边- … \dots …
根据存储结构的不同,操作的定义也不同