1.图的定义
图(Graph)是由非空的顶点集合和一个描述顶点之间关系――边(或者弧)的集合组成,其形式化定义为:
G=(V,E)
V={vi| vi∈dataobject}
E={( vi,vj)| vi, vj ∈V ∧P(vi, vj)}
其中,G 表示一个图,V 是图G 中顶点的集合,E 是图G 中边的集合,集合E 中P(vi,vj)表示顶点vi 和顶点vj 之间有一条直接连线,即偶对(vi,vj)表示一条边。图8.1 给出了一个图的示例,在该图中:
集合V={v1,v2,v3,v4,v5};
集合E={(v1,v2),(v1,v4),(v2,v3),(v3,v4),(v3,v5),(v2,v5)}。
(1)无向图。在一个图中,如果任意两个顶点构成的偶对(vi, vj)∈E 是无序的,即顶点之间的连线是没有方向的,则称该图为无向图。如图8.1 所示是一个无向图G1。
(2)有向图。在一个图中,如果任意两个顶点构成的偶对(vi, vj)∈E 是有序的,即顶点之间的连线是有方向的,则称该图为有向图。如图8.2 所示是一个有向图G2:
G2=(V2,E2)
V2={v1,v2,v3,v4}
E2={<v1,v2>,<v1,v3>,<v3,v4>,<v4,v1>}
(3)顶点、边、弧、弧头、弧尾。图中,数据元素vi 称为顶点(vertex );P(vi, vj)表示在顶点vi 和顶点vj 之间有一条直接连线。如果是在无向图中,则称这条连线为边;如果是在有向图中,一般称这条连线为弧。边用顶点的无序偶对(vi, vj)来表示,称顶点vi和顶点vj 互为邻接点,边(vi, vj)依附于顶点vi 与顶点vj;弧用顶点的有序偶对<vi, vj>来表示,有序偶对的第一个结点vi 被称为始点(或弧尾),在图中就是不带箭头的一端;有序偶对的第二个结点vj 被称为终点(或弧头),在图中就是带箭头的一端。
(4)无向完全图。在一个无向图中,如果任意两顶点都有一条直接边相连接,则称该图为无向完全图。可以证明,在一个含有n 个顶点的无向完全图中,有n(n-1)/2 条边。
(5)有向完全图。在一个有向图中,如果任意两顶点之间都有方向互为相反的两条弧相连接,则称该图为有向完全图。在一个含有n 个顶点的有向完全图中,有n(n-1)条边。
(6)稠密图、稀疏图。若一个图接近完全图,称为稠密图;称边数很少的图为稀疏图。
(7)顶点的度、入度、出度。顶点的度(degree)是指依附于某顶点v 的边数,通常记为TD (v)。在有向图中,要区别顶点的入度与出度的概念。顶点v 的入度是指以顶点为终点的弧的数目。记为ID (v);顶点v 出度是指以顶点v 为始点的弧的数目,记为OD (v)。
有TD (v)=ID (v)+OD (v)。
例如,在G1 中有:
TD(v1)=2 TD(v2)=3 TD(v3)=3 TD(v4)=2 TD(v5)=2
在G2 中有:
ID(v1)=1 OD(v1)=2 TD(v1)=3
ID(v2)=1 OD(v2)=0 TD(v2)=1
ID(v3)=1 OD(v3)=1 TD(v3)=2
ID(v4)=1 OD(v4)=1 TD(v4)=2
可以证明,对于具有n 个顶点、e 条边的图,顶点vi 的度TD (vi)与顶点的个数以及边的数目满足关系:
(9)路径、路径长度。顶点vp 到顶点vq 之间的路径(path)是指顶点序列vp,vi1,vi2, …,vim,vq.。其中,(vp,vi1),(vi1,vi2),…,(vim,.vq)分别为图中的边。路径上边的数目称为路径长度。图8.1 所示的无向图G1 中,v1→v4→v3→v5 与v1→v2→v5 是从顶点v1 到顶点v5 的两条路径,路径长度分别为3 和2。
(10)回路、简单路径、简单回路。称vi 的路径为回路或者环(cycle)。序列中顶点不重复出现的路径称为简单路径。在图8.1 中,前面提到的v1 到v5 的两条路径都为简单路径。除第一个顶点与最后一个顶点之外,其他顶点不重复出现的回路称为简单回路,或者简单环。如图8.2 中的v1→v3→v4→v1。
(11)子图。对于图G=(V,E),G’=(V’,E’),若存在V’是V 的子集,E’是E的子集,则称图G’是G 的一个子图。图8.4 示出了G2 和G1 的两个子图G’和G’’。
(13)强连通图、强连通分量。对于有向图来说,若图中任意一对顶点vi 和vj(i≠j)均有从一个顶点vi 到另一个顶点vj 有路径,也有从vj 到vi 的路径,则称该有向图是强连通图。有向图的极大强连通子图称为强连通分量。图8.2 中有两个强连通分量,分别是{v1,v2,v3}和{v4},如图8.6 所示。
(14)生成树。所谓连通图G 的生成树,是G 的包含其全部n 个顶点的一个极小连通子图。它必定包含且仅包含G 的n-1 条边。图8.4(b)G”示出了图8.1(a)中G1 的一棵生成树。在生成树中添加任意一条属于原图中的边必定会产生回路,因为新添加的边使其所依附的两个顶点之间有了第二条路径。若生成树中减少任意一条边,则必然成为非连通的。
(15)生成森林。在非连通图中,由每个连通分量都可得到一个极小连通子图,即一棵生成树。这些连通分量的生成树就组成了一个非连通图的生成森林。
(1) CreatGraph(G)输入图G 的顶点和边,建立图G 的存储。
(2)DestroyGraph(G)释放图G 占用的存储空间。
(3)GetVex(G,v)在图G 中找到顶点v,并返回顶点v 的相关信息。
(4)PutVex(G,v,value)在图G 中找到顶点v,并将value 值赋给顶点v。
(5)InsertVex(G,v)在图G 中增添新顶点v。
(6)DeleteVex(G,v)在图G 中,删除顶点v 以及所有和顶点v 相关联的边或弧。
(7)InsertArc(G,v,w)在图G 中增添一条从顶点v 到顶点w 的边或弧。
(8)DeleteArc(G,v,w)在图G 中删除一条从顶点v 到顶点w 的边或弧。
(9)DFSTraverse(G,v)在图G 中,从顶点v 出发深度优先遍历图G。
(10)BFSTtaverse(G,v)在图G 中,从顶点v 出发广度优先遍历图G。
在一个图中,顶点是没有先后次序的,但当采用某一种确定的存储方式存储后,存储结构中顶点的存储次序构成了顶点之间的相对次序,这里用顶点在图中的位置表示该顶点的存储顺序;同样的道理,对一个顶点的所有邻接点,采用该顶点的第i 个邻接点表示与该顶点相邻接的某个顶点的存储顺序,在这种意义下,图的基本操作还有:
(11)LocateVex(G,u)在图G 中找到顶点u,返回该顶点在图中位置。
(12)FirstAdjVex(G,v)在图G 中,返回v 的第一个邻接点。若顶点在G 中没有邻接顶点,则返回“空”。
(13)NextAdjVex(G,v,w)在图G 中,返回v 的(相对于w 的)下一个邻接顶点。若w 是v 的最后一个邻接点,则返回“空”。