1. 什么是图?
在离散数学中,图(Graph)是用于表示物体与物体之间存在某种关系的结构。数学抽象后的“物体”称作节点或顶点(英語:Vertex,node或point),节点间的相关关系则称作边。在描绘一张图的时候,通常用一组点或小圆圈表示节点,其间的边则使用直线或曲线。
图中的边可以是有方向或没有方向的。例如在一张图中,如果节点表示聚会上的人,而边表示两人曾经握手,则该图就是没有方向的,因为甲和乙握过手也意味着乙一定和甲握过手。相反,如果一条从甲到乙的边表示甲欠乙的钱,则该图就是有方向的,因为“曾经欠钱”这个关系不一定是双向的。前一种图称为无向图,后一种称为有向图。
2. 图的基本概念
图(graphy)是由顶点集合及顶点间的关系组成的一种数据结构:
G = (V
,
E)
,其中:
顶点(vertex)集合V = {x|x
属于某个数据对象集
}
是有穷非空集合
;
边(edge)集合E = {(x,y)|x,y
属于
V}
或者
E = {<x, y>|x,y
属于
V && Path(x, y)}
是顶点间关系的有穷集合
。
(x, y)
表示
x
到
y
的一条双向通路,即
(x, y)
是无方向的;
Path(x, y)
表示从
x
到
y
的一条单向通路,即Path(x, y)是有方向的。
顶点和边:
图中结点称为顶点
,第
i
个顶点记作
vi
。
两个顶点
vi
和
vj
相关联称作顶点
vi
和顶点
vj
之间
有一条边
,图中的第
k
条边记作
ek
,
ek = (vi
,
vj)
或
<vi
,
vj>
。
有向图和无向图:
在有向图中,顶点对
<x, y>
是有序的,顶点对
<x
,
y>
称为顶点
x
到顶点
y
的一条
边
(
弧
)
,
<x, y>
和
<y, x>
是两条不同的边
,比如下图
G3
和
G4
为有向图。在
无向图中,顶点对
(x, y)
是无序的,顶点对
(x,y)
称为顶点
x
和顶点
y
相关联的一条边,这条边没有特定方向,
(x, y)
和
(y
,
x)
是同一条边
,比如下图
G1
和
G2
为无向图。注意:
无向边
(x, y)
等于有向边
<x, y>
和
<y, x>
。

完全图:在
有
n
个顶点的无向图中
,若
有
n * (n-1)/2
条边
,即
任意两个顶点之间有且仅有一条边
,则称此图为无向完全图
,比如上图
G1
;在
n
个顶点的有向图
中,若
有
n * (n-1)
条边
,即
任意两个
顶点之间有且仅有方向相反的边
,则称此图为
有向完全图
,比如上图
G4
。
邻接顶点:在
无向图中
G
中,若
(u, v)
是
E(G)
中的一条边,则称
u
和
v
互为邻接顶点
,并称
边
(u,v)
依
附于顶点
u
和
v
;在
有向图
G
中,若
<u, v>
是
E(G)
中的一条边,则称顶点
u
邻接到
v
,顶点
v
邻接自顶
点
u
,并称边
<u, v>
与顶点
u
和顶点
v
相关联
。
顶点的度:
顶点
v
的度是指与它相关联的边的条数,记作
deg(v)
。在有向图中,
顶点的度等于该顶
点的入度与出度之和
,其中顶点
v
的
入度是以
v
为终点的有向边的条数
,记作
indev(v);
顶点
v
的
出度
是以
v
为起始点的有向边的条数
,记作
outdev(v)
。因此:
dev(v) = indev(v) + outdev(v)
。注意:对于无向图,顶点的度等于该顶点的入度和出度
,即
dev(v) = indev(v) = outdev(v)
。
路径:在图
G = (V
,
E)
中,若
从顶点
vi
出发有一组边使其可到达顶点
vj
,则称顶点
vi
到顶点
vj
的顶
点序列为从顶点
vi
到顶点
vj
的路径
。
路径长度:对于
不带权的图,一条路径的路径长度是指该路径上的边的条数
;对于
带权的图,一
条路
径的路径长度是指该路径上各个边权值的总和
。
简单路径与回路:
若路径上各顶点
v1
,
v2
,
v3
,
…
,
vm
均不重复,则称这样的路径为简单路
径
。
若路
径上第一个顶点
v1
和最后一个顶点
vm
重合,则称这样的路径为回路或环
。如

子图:
设图
G = {V, E}
和图
G1 = {V1
,
E1}
,若
V1
属于
V
且
E1
属于
E
,则称
G1
是
G
的子图
。

连通图:在
无向图
中,若从顶点
v1
到顶点
v2
有路径,则称顶点
v1
与顶点
v2
是连通的。
如果图中任
意一
对顶点都是连通的,则称此图为连通图
。
强连通图:在
有向图
中,若在
每一对顶点
vi
和
vj
之间都存在一条从
vi
到
vj
的路径,也存在一条从
vj
到
vi
的路径,则称此图是强连通图
。
生成树:一个
连通图的最小连通子图
称作该图的生成树。
有
n
个顶点的连通图的生成树有
n
个顶点
和
n-
1
条边
。
3. 图的存储结构
这之前我们已经学过了树这种数据结构,对于一棵树来说最值得关心的就是每个节点,那么同样的,对于一张图来说最值得关心的就是每个顶点和边,在这里我们有两种方式来表示
1. 邻接矩阵
因为节点与节点之间的关系就是连通与否,即为
0
或者
1
,因此
邻接矩阵
(
二维数组
)
即是:先用一
个数组将定点保存,然后采用矩阵来表示节点与节点之间的关系
。即

注意:
1.
无向图的邻接矩阵是对称的
,
第
i
行
(
列
)
元素之和,就是顶点
i
的度
。
有向图的邻接矩阵则不一
定是对称的,第
i
行
(
列
)
元素之后就是顶点
i
的出
(
入
)
度
。
2.
如果边带有权值,并且两个节点之间是连通的,上图中的边的关系就用权值代替,如果两个顶点不通,则使用无穷大代替,即

3. 综合来说,邻接矩阵更加适合稠密图,即顶点与顶点间的边较多,也更加适合判断顶点与顶点间是否联通,而不适合查找一个顶点连接的所有边。
2. 邻接表
邻接表:使用数组表示顶点的集合,
使用链表表示边的关系
。
1.
无向图邻接表存储

注:
无向图中同一条边在邻接表中出现了两次。如果想知道顶点
vi
的度,只需要知道顶点
vi
边链表集合中结点的数目即可
。
2.
有向图邻接表存储

注:有向图中每条边在邻接表中只出现一次,与顶点
vi
对应的邻接表所含结点的个数,就是该顶点的出度,也称出度表,要得到vi
顶点的入度,必须检测其他所有顶点对应的边链表,看有多少边顶点的dst
取值是
i
。
综合来说,邻接表更加适合稀疏图,即顶点之间有较少的边联通的情况,它更加适合查找一个顶点所对应的所有边,而不适合判断两个顶点之间是否互相联通。