数据结构 第 7 章 图

125
数数数数 1 数数数数 数7数 数数数数?? 数数数数 数数数数数数

description

数据结构 第 7 章 图. 什么是图?? 图的遍历 最短路径算法. 图( Graph )是一种较线性表和树更为复杂的非线性结构。在图结构中,对结点(图中常称为顶点)的前趋和后继个数都是不加限制的,即结点之间的关系是任意的。图中任意两个结点之间都可能相关。 图的应用极为广泛,特别是近年来的迅速发展,已渗透到诸如语言学、逻辑学、物理、化学、电讯工程、计算机科学以及数学的其它分支中。. 图. 图是由一个非空的顶点集合和一个描述顶点之间多对多关系的边(或弧)集合组成的一种数据结构,它可以形式化地表示为: 图=( V , E ) - PowerPoint PPT Presentation

Transcript of 数据结构 第 7 章 图

Page 1: 数据结构 第 7 章  图

数据结构 1

数据结构第 7 章 图

什么是图??

图的遍历

最短路径算法

Page 2: 数据结构 第 7 章  图

数据结构 2

图( Graph )是一种较线性表和树更为复杂的非线性结构。在图结构中,对结点(图中常称为顶点)的前趋和后继个数都是不加限制的,即结点之间的关系是任意的。图中任意两个结点之间都可能相关。

图的应用极为广泛,特别是近年来的迅速发展,已渗透到诸如语言学、逻辑学、物理、化学、电讯工程、计算机科学以及数学的其它分支中。

Page 3: 数据结构 第 7 章  图

数据结构 3

图 图是由一个非空的顶点集合和一个描述顶图是由一个非空的顶点集合和一个描述顶点之间多对多关系的边(或弧)集合组成点之间多对多关系的边(或弧)集合组成的一种数据结构,它可以形式化地表示为:的一种数据结构,它可以形式化地表示为:图=(图=( VV ,, EE ))

其中其中 V={x|xV={x|x 某个数据对象集某个数据对象集 }} ,它是,它是顶点的有穷非空集合;顶点的有穷非空集合; E={E={ (( xx ,, yy )) ||xx ,, yyV}V} 或或 E={<xE={<x ,, y>|xy>|x ,, yyVV 且且 PP(( xx ,, yy )) }} ,它是顶点之间关系的有穷,它是顶点之间关系的有穷集合,也叫做边集合,集合,也叫做边集合, PP (( xx ,, yy )表示)表示从从 xx 到到 yy 的一条单向通路。的一条单向通路。

Page 4: 数据结构 第 7 章  图

数据结构 4

图的应用举例图的应用举例

例例 1 1 交通图(公路、铁路)交通图(公路、铁路) 顶点:地点顶点:地点 边:连接地点的公路边:连接地点的公路 交通图中的有单行道双行道,分别用有向边、无向边表示;交通图中的有单行道双行道,分别用有向边、无向边表示;

V0

V4 V3

V1

V2

V0 V1

V2 V3

例例 2 2 电路图电路图 顶点:元件顶点:元件 边:连接元件之间的线路边:连接元件之间的线路

例例 3 3 通讯线路图通讯线路图 顶点:地点顶点:地点 边:地点间的连线边:地点间的连线例例 4 4 各种流程图各种流程图 如产品的生产流程图如产品的生产流程图 顶点:工序顶点:工序 边:各道工序之间的顺序关系边:各道工序之间的顺序关系

Page 5: 数据结构 第 7 章  图

数据结构 5

通常,也将图通常,也将图 GG 的顶点集和边集分别记为的顶点集和边集分别记为 VV(( GG )和)和 EE (( GG )。)。 EE (( GG )可以是空集,若)可以是空集,若 EE(( GG )为空,则图)为空,则图 GG 只有顶点而没有边。只有顶点而没有边。

若图若图 GG 中的每条边都是有方向的,则称中的每条边都是有方向的,则称 GG 为为有向图有向图。。在有向图中,一条有向边是由两个顶点组成的有序对,在有向图中,一条有向边是由两个顶点组成的有序对,有序对通常用尖括号表示。例如,有序对有序对通常用尖括号表示。例如,有序对 <v<vii ,, vvjj>>表示一条由表示一条由 vvii 到到 vvjj 的有向边。有向边又称为的有向边。有向边又称为弧弧,弧,弧的始点称为的始点称为弧尾弧尾,弧的终点称为,弧的终点称为弧头弧头。。若图若图 GG 中的每条边都是没有方向的,则称中的每条边都是没有方向的,则称 GG 为为无向无向图图。无向图中的边均是顶点的无序对,无序对通常用。无向图中的边均是顶点的无序对,无序对通常用圆括号表示。 圆括号表示。

Page 6: 数据结构 第 7 章  图

数据结构 6

v1 v2

v3 v4

v1 v2

v4 v5

v3

(( aa )有向图)有向图 GG11 (( bb )无向)无向图图 GG22

(( aa )表示的是有向图)表示的是有向图 GG11 ,该图的顶点集和边集分,该图的顶点集和边集分别为:别为:VV (( GG11 )) ={v={v11 ,, vv22 ,, vv33 ,, vv44}}

EE (( GG11 )) ={<v={<v11 ,, vv22>> ,, <v<v11 ,, vv33>> ,, <v<v22 ,, vv44>> ,, <v<v33 ,, vv22>}>}

有序对有序对 <v<vii,v,vjj> > ::用以用以 vvii 为起点、以为起点、以 vvjj 为终点为终点的有向线段表示,称为有向的有向线段表示,称为有向

边或弧;边或弧;

Page 7: 数据结构 第 7 章  图

数据结构 7

v1 v2

v3 v4

v1 v2

v4 v5

v3

(( aa )有向图)有向图 GG11 (( bb )无向)无向图图 GG22 (( bb )表示的是无向图)表示的是无向图 GG22 ,该图的顶点集和边集分,该图的顶点集和边集分

别为:别为:

VV (( GG22 )) ={v={v11 ,, vv22 ,, vv33 ,, vv44 ,, vv55}}

EE (( GG22 )) ={={ (( vvll ,, vv22 ),(),( vv11 ,, vv33 ),(),( vv11 ,, vv44 ),(),( vv22 ,, vv33 ),(),( vv22 ,, vv55 ),(),( vv44 ,, vv55 )) }}

无序对无序对 (v(vii,v,vjj)) ::

用连接顶点用连接顶点 vvii 、、 vvjj 的线段的线段表示,称为无向边;表示,称为无向边;

Page 8: 数据结构 第 7 章  图

数据结构 8

在以后的讨论中,我们约定:在以后的讨论中,我们约定:

(( 11 )一条边中涉及的两个顶点必须不相同,)一条边中涉及的两个顶点必须不相同,即:若(即:若( vvii ,, vvjj )或)或 <v<vii ,, vvjj>> 是是 EE (( GG ))中的一条边,则要求中的一条边,则要求 vvii≠v≠vjj ;;

(( 22 )在有向图中,一对顶点间不能有相同)在有向图中,一对顶点间不能有相同方向的两条有向边;方向的两条有向边;

(( 33 ))在无向图中,在无向图中,一对顶点间不能有两条一对顶点间不能有两条无向边。 无向边。

Page 9: 数据结构 第 7 章  图

数据结构 9

完全图 若用若用 nn 表示图中顶点的数目,用表示图中顶点的数目,用 ee 表示图表示图中边的数目,按照上述规定,容易得到下中边的数目,按照上述规定,容易得到下述结论:述结论:对于一个具有对于一个具有 nn 个顶点的有向图,其边数个顶点的有向图,其边数 ee 小小于等于于等于 nn (( n-1n-1 ),边数恰好等于),边数恰好等于 nn (( n-1n-1 ))的有向图称为的有向图称为有向完全图有向完全图。。

对于一个具有对于一个具有 nn 个顶点的无向图,其边数个顶点的无向图,其边数 ee 小小于等于于等于 nn (( n-1n-1 )) /2/2 ,边数恰好等于,边数恰好等于 nn (( n-n-11 )) /2/2 的无向图称为的无向图称为无向完全图无向完全图;;

也就是说完全图具有最多的边数,任意一也就是说完全图具有最多的边数,任意一对顶点间均有边相连。对顶点间均有边相连。

Page 10: 数据结构 第 7 章  图

数据结构 10

v1

v2 v3

v4

v1

v2 v3

v4

(( aa )无向完全图)无向完全图 GG33 (( bb )有向完全)有向完全图图 GG44 上图所示的上图所示的 GG33 与与 GG44 分别是具有分别是具有 44 个顶点的个顶点的

无向完全图和有向完全图。图无向完全图和有向完全图。图 GG33 共有共有 44 个顶点个顶点 66 条条边;图边;图 GG44 共有共有 44 个顶点个顶点 1212 条边。 条边。 若(若( vvii ,, vvjj )是一条无向边,则称顶点)是一条无向边,则称顶点 vvii

和和 vvjj 互为邻接点互为邻接点 (Adjacent) ,或称 vi 和 vj 相邻接;称 (vi , vj)依附 (Incident) 于顶点 vi 和 vj ,或称 (vi , vj) 与顶点 vi 和 vj 相关联。

Page 11: 数据结构 第 7 章  图

数据结构 11

度、入度、出度 在无向图中,一个顶点的在无向图中,一个顶点的度度就是与该顶点相关联就是与该顶点相关联

的边的数目,顶点的边的数目,顶点 vv 的度记为的度记为 DD(( vv )。)。 例如在上页图(例如在上页图( aa )所示的无向图)所示的无向图 G3G3 中,各顶点的中,各顶点的度均为度均为 33 。。

在有向图中,则把以顶点在有向图中,则把以顶点 vv 为终点的边的数目称为终点的边的数目称为顶点为顶点 vv 的的入度入度,记为,记为 IDID(( vv );把以顶点);把以顶点 vv为始点的边的数目称为为始点的边的数目称为 vv 的的出度出度,记为,记为 ODOD(( vv ),有向图中顶点的度数等于顶点的入度与),有向图中顶点的度数等于顶点的入度与出度之和,即出度之和,即 DD(( vv )) =ID=ID(( vv )) +OD+OD(( vv )。)。 例如在上页图(例如在上页图( bb )所示的有向图)所示的有向图 G4G4 中,各顶点的中,各顶点的度均为度均为 66 。 。

Page 12: 数据结构 第 7 章  图

数据结构 12

无论有向图还是无向图,图中的每条边均关无论有向图还是无向图,图中的每条边均关联于两个顶点,因此,顶点数联于两个顶点,因此,顶点数 nn 、边数、边数 ee 和和度数之间有如下关系:度数之间有如下关系:

n

iivD

1

)(2

1e=e=

Page 13: 数据结构 第 7 章  图

数据结构 13

子图 给定两个图给定两个图 GiGi 和和 GjGj ,其中,其中 Gi=Gi= (( ViVi ,,EiEi ),), Gj=Gj= (( VjVj ,, EjEj ),若满足),若满足 ViViVVjj ,, EiEiEjEj ,则称,则称 GiGi 是是 GjGj 的的子图子图。。

Page 14: 数据结构 第 7 章  图

数据结构 14

v1 v2

v4

v2 v3

v4

v1

v2 v3

v4

v1

v4

v2 v3

v4

v1 v1

v3v2

v4

子图示例子图示例

(( aa )无向图)无向图 GG33 的部分子图 的部分子图

(( bb )有向图)有向图 GG44 的部分子图 的部分子图

v1

v2 v3

v4

v1

v2 v3

v4

Page 15: 数据结构 第 7 章  图

数据结构 15

路径 无向图无向图 GG 中若存在着一个顶点序列中若存在着一个顶点序列 vv 、、 v1’v1’、、v2’v2’、…、、…、 vm’vm’、、 uu,且(,且( vv ,, v1’v1’)、)、(( v1’v1’,, v2’v2’)、…、()、…、( vm’vm’,, uu)均)均属于属于 EE (( GG ),则称该顶点序列为顶点),则称该顶点序列为顶点 vv 到到顶点顶点 uu的一条的一条路径路径,相应地,顶点序列,相应地,顶点序列 uu、、vm’vm’、、 vm-1’vm-1’、…、、…、 v1’v1’、、 vv 是顶点是顶点 uu到到顶点顶点 vv 的一条路径。的一条路径。

如果如果 GG 是有向图,路径也是有向的,它由是有向图,路径也是有向的,它由 EE(( GG )中的有向边)中的有向边 <v<v ,, v1’>v1’> 、、 <v1’<v1’,, vv2’>2’> 、…、、…、 <vm’<vm’,, u>u> 组成。组成。

Page 16: 数据结构 第 7 章  图

数据结构 16

路径长度路径长度是该路径上边或弧的数目。是该路径上边或弧的数目。

如果一条路径上除了起点如果一条路径上除了起点 vv 和终点和终点 uu 相同相同外,其余顶点均不相同,则称此路径为一外,其余顶点均不相同,则称此路径为一条条简单路径简单路径。起点和终点相同(。起点和终点相同( v=uv=u )的)的简单路径称为简单路径称为简单回路简单回路或或简单环简单环。。

Page 17: 数据结构 第 7 章  图

数据结构 17

连通图与强连通图 在无向图在无向图 GG 中,若从顶点中,若从顶点 vvii 到顶点到顶点 vvjj 有路径,有路径,则称则称 vvii 与与 vvjj 是连通的。若是连通的。若 VV (( GG )中任意两个不)中任意两个不同的顶点同的顶点 vvii 和和 vvjj 都连通(即有路径),则称都连通(即有路径),则称 GG 为为连通图连通图。例如,。例如, P6P6 (( bb )所示的无向图)所示的无向图 GG22 、、 P10P10(( aa )所示的无向图)所示的无向图 GG33 是都是连通图。 是都是连通图。 无向图无向图 GG 的极大连通子图称为的极大连通子图称为 GG 的的连通分量连通分量。。根据连通分量的定义,可知任何连通图的连通分根据连通分量的定义,可知任何连通图的连通分量是其自身,非连通的无向图有多个连通分量。 量是其自身,非连通的无向图有多个连通分量。

Page 18: 数据结构 第 7 章  图

数据结构 18

例:非连通图及其连通分量示例例:非连通图及其连通分量示例

(( aa )非连通图)非连通图 GG55 (( bb )) GG55 的两个连通分量的两个连通分量 HH11 和和 HH22

V1 V2

V4

V5

V3

V1 V2

V4

V5

V3

Page 19: 数据结构 第 7 章  图

数据结构 19

在有向图在有向图 GG 中,若对于中,若对于 VV (( GG )中任意两)中任意两个不同的顶点个不同的顶点 vivi 和和 vjvj ,都存在从,都存在从 vivi 到到 vjvj以及从以及从 vjvj 到到 vivi 的路径,则称的路径,则称 GG 是是强连通强连通图。图。

有向图的极大强连通子图称为有向图的极大强连通子图称为 GG 的强连通的强连通分量。分量。

据强连通图的定义,可知强连通图的唯一据强连通图的定义,可知强连通图的唯一强连通分量是其自身,而非强连通的有向强连通分量是其自身,而非强连通的有向图有多个强连通分量。图有多个强连通分量。

Page 20: 数据结构 第 7 章  图

数据结构 20

vv11

vv22

vv33 vv44

vv11

vv22

vv33 vv44

(( aa )非强连通图)非强连通图 GG66 (( bb )) GG66 的两个强连通分量的两个强连通分量 HH33和和 HH44

v1

v2 v3

v4

Page 21: 数据结构 第 7 章  图

数据结构 21

网络有时在图的每条边上附上相关的数值,这种与图有时在图的每条边上附上相关的数值,这种与图的边相关的数值叫的边相关的数值叫权权。 。 权可以表示两个顶点之间的距离、耗费等具有某权可以表示两个顶点之间的距离、耗费等具有某种意义的数。若将图的每条边都赋上一个权,则称种意义的数。若将图的每条边都赋上一个权,则称这种带权图为这种带权图为网络网络 (Network)(Network) 。 。

V0

V1 V3

V234

56 78 25

V0

V2V1 455064

(( aa )无向网络)无向网络 GG77 (( bb )有向网络)有向网络 GG88

Page 22: 数据结构 第 7 章  图

数据结构 22

图的基本运算图是一种复杂数据结构,由图的定义及图的图是一种复杂数据结构,由图的定义及图的一组基本操作构成了图的抽象数据类型。一组基本操作构成了图的抽象数据类型。

ADT Graph{ADT Graph{数据对象数据对象 VV :: VV 是具有相同特性的数据元素是具有相同特性的数据元素的集合,称为顶点集。的集合,称为顶点集。数据关系数据关系 RR ::R={<vR={<v ,, w>|vw>|v ,, wwVV 且且 PP (( vv ,, ww ),), PP(( vv ,, ww )定义了边(或弧))定义了边(或弧) <v<v ,, w>w> 的信的信息息 }}

Page 23: 数据结构 第 7 章  图

数据结构 23

图的基本操作如下:图的基本操作如下:

(( 11 )) creatgraphcreatgraph (( &g&g ) 创建一个图的存储结构。) 创建一个图的存储结构。

(( 22 )) insertvertexinsertvertex (( &g&g ,, vv ) 在图) 在图 gg 中增加一中增加一个顶点个顶点 vv 。。

(( 33 )) deletevertexdeletevertex (( &g&g ,, vv ) 在图) 在图 gg 中删除顶中删除顶点点 vv 及所有和顶点及所有和顶点 vv 相关联的边或弧。相关联的边或弧。

(( 44 )) insertedgeinsertedge (( &g&g ,, vv ,, uu ) 在图) 在图 gg 中增加一中增加一条从顶点条从顶点 vv 到顶点到顶点 uu的边或弧。的边或弧。

(( 55 )) deleteedgedeleteedge (( &g&g ,, vv ,, uu ) 在图) 在图 gg 中删除一中删除一条从顶点条从顶点 vv 到顶点到顶点 uu的边或弧。的边或弧。

Page 24: 数据结构 第 7 章  图

数据结构 24

(( 66 )) travetrave (( gg) 遍历图) 遍历图 gg。。

(( 77 )) locatevertexlocatevertex (( gg ,, vv ) 求顶点) 求顶点 vv 在图在图 gg中的位序。中的位序。

(( 88 )) firstvertexfirstvertex (( gg ,, vv ) 求图) 求图 gg 中顶点中顶点 vv的第一个邻接点。的第一个邻接点。

(( 99 )) degreedegree (( gg ,, vv ) 求图) 求图 gg 中顶点中顶点 vv 的的度数。度数。

(( 1010 )) nextvertexnextvertex (( gg ,, vv ,, ww ) 求图) 求图 gg 中与顶中与顶点点 vv 相邻接的顶点相邻接的顶点 ww 的下一个邻接点。即求图的下一个邻接点。即求图 gg 中中顶点顶点 vv 的某个邻接点,它的存储顺序排在邻接点的某个邻接点,它的存储顺序排在邻接点 ww的存储位置之后。的存储位置之后。

} ADT Graph} ADT Graph

Page 25: 数据结构 第 7 章  图

数据结构 25

图的存储结构

图的存储结构至少要保存两类信息:图的存储结构至少要保存两类信息: 1)1) 顶点的数据顶点的数据 2)2) 顶点间的关系顶点间的关系

约定 : G=<V, E>G=<V, E> 是图是图 , V={v, V={v00,v,v11,v,v22, … v, … vn-1n-1 }, }, 设顶点的设顶点的 角标为它的编号角标为它的编号

如何表示顶点间的关系?如何表示顶点间的关系?

V0

V4

V3

V1

V2

V0

V1

V2

V3

Page 26: 数据结构 第 7 章  图

数据结构 26

1.1. 邻接矩阵及其实现邻接矩阵及其实现 (数组表示(数组表示法)法)

给定图给定图 G=G= (( VV ,, EE ),其中),其中 VV (( GG )) ={v={v00 ,,…,…, vvii ,…,,…, vvn-1n-1}} ,, GG 的邻接矩阵(的邻接矩阵( Adjacency MAdjacency Matrixatrix )是具有如下性质的)是具有如下性质的 nn阶方阵: 阶方阵:

,

),( , ,][A

否则或者如果

0

><1 EjiEjiji,

无向图的邻接矩阵是对称的,有向图的邻无向图的邻接矩阵是对称的,有向图的邻接矩阵可能是不对称的。接矩阵可能是不对称的。

一、非网络的邻接矩阵一、非网络的邻接矩阵

Page 27: 数据结构 第 7 章  图

数据结构 27

v0

v1 v3

v2

v3

v1

v0 v2

图的邻接矩阵示例图的邻接矩阵示例

0 1 1 0 1 1 11

1 0 1 1 0 1 00

1 1 0 1 1 0 11

1 0 1 1 0 1 00

0 1 0 0 1 0 00

1 0 1 1 0 1 00

1 1 0 1 1 0 00

0 1 0 0 1 0 00

A1=A1= A2=A2=

无向图无向图 GG99 及有向图及有向图 GG1010 的邻接矩阵表示 的邻接矩阵表示

Page 28: 数据结构 第 7 章  图

数据结构 28

用邻接矩阵表示图,很容易判定任意两个顶点之用邻接矩阵表示图,很容易判定任意两个顶点之间是否有边相连,并求得各个顶点的度数。间是否有边相连,并求得各个顶点的度数。对于无向图,顶点对于无向图,顶点 vvii 的度数是邻接矩阵中第的度数是邻接矩阵中第 ii 行行或第或第 ii列值为列值为 11 的元素个数,即: 的元素个数,即:

DD (( vvii )) = == =

1

0

],[n

j

jiA

1

0

],[n

j

ijA

对于有向图,邻接矩阵中第对于有向图,邻接矩阵中第 ii 行值为行值为 11 的元素个的元素个数为顶点数为顶点 vvii 的出度,第的出度,第 ii列值为列值为 11 的元素的个数的元素的个数为顶点为顶点 vvii 的入度,即: 的入度,即:

ODOD (( vvii )) = ; ID= ; ID (( vvii ) ) ==

1

0

],[n

j

jiA

1

0

],[n

j

ijA

Page 29: 数据结构 第 7 章  图

数据结构 29

二、网络的邻接矩阵二、网络的邻接矩阵

当当 G=G= (( VV ,, EE )是一个网络时,)是一个网络时, GG 的邻接矩阵是的邻接矩阵是具有如下性质的具有如下性质的 nn阶方阵: 阶方阵:

WWijij 当(当( vvii ,, vvjj )或)或 < v< vii ,, vvjj > >EE (( GG ))

∞ ∞ 当(当( vvii ,, vvjj )或)或 < v< vii ,, vvjj > >!!EE (( GG ))

A[iA[i ,, jj]=]=

其中其中 WWijij 表示边上的权值;∞表示一个计算机表示边上的权值;∞表示一个计算机允许的、大于所有边上权值的数。 允许的、大于所有边上权值的数。

Page 30: 数据结构 第 7 章  图

数据结构 30

V0

V1 V3

V234

56 78 25

V0

V2V1 455064

网络的邻接矩阵示例网络的邻接矩阵示例

∞∞ 56 34 7856 34 78

56 56 ∞ ∞ ∞ ∞ ∞ ∞

34 ∞ 34 ∞ ∞ ∞ 25 25

78 ∞ 25 78 ∞ 25 ∞∞

∞∞ ∞ ∞ 5050

∞∞ ∞ ∞ 4545

64 ∞ 64 ∞ ∞∞

AA33== AA44==

(( aa )) GG77 的邻接矩阵 (的邻接矩阵 ( bb )) GG88 的邻接矩的邻接矩阵阵

网络邻接矩阵示例网络邻接矩阵示例

Page 31: 数据结构 第 7 章  图

数据结构 31

邻接矩阵存储结构邻接矩阵存储结构#define INFINITY 5000 /*#define INFINITY 5000 /* 此处用此处用 50005000 代表无穷大代表无穷大*/*/

#define MAX_VERTEX_NUM 20 /*#define MAX_VERTEX_NUM 20 /*最大顶点数最大顶点数 */*/

typedef char vertextype; /*typedef char vertextype; /*顶点值类型顶点值类型 */*/

typedef int edgetype; /*typedef int edgetype; /* 权值类型权值类型 */*/

typedef struct{typedef struct{

vertextype vexs[vertextype vexs[MAX_VERTEX_NUMMAX_VERTEX_NUM]; /*]; /*顶点信息域顶点信息域 */*/

edgetype edges[edgetype edges[MAX_VERTEX_NUMMAX_VERTEX_NUM][][MAX_VERTEX_NUMMAX_VERTEX_NUM]; ];

/*/*邻接矩阵邻接矩阵 */*/

int vexnum,arcnum; /*int vexnum,arcnum; /*图中顶点总数与边数图中顶点总数与边数 */*/

} MGraph; /*} MGraph; /*邻接矩阵表示的图类型邻接矩阵表示的图类型 */*/

Page 32: 数据结构 第 7 章  图

数据结构 32

/* /* 图的邻接矩阵创建算法 函数名:图的邻接矩阵创建算法 函数名: creatmgraph1()creatmgraph1() */ */

#include <stdio.h>#include <stdio.h>

#include “MGraph.h”#include “MGraph.h”

void creatmgraph1(MGraph *g)void creatmgraph1(MGraph *g){ int i,j,k,w; { int i,j,k,w; /*/* 建立有向网络的邻接矩阵存储结构建立有向网络的邻接矩阵存储结构 */*/

printf("please input vexnum and arcnum:\n");printf("please input vexnum and arcnum:\n");

scanf("%d%d",&g->vexnum,&g->arcnum);scanf("%d%d",&g->vexnum,&g->arcnum);

/*/* 输入图的顶点数与边数输入图的顶点数与边数 */*/

printf("please input vexs:\n");printf("please input vexs:\n");

Page 33: 数据结构 第 7 章  图

数据结构 33

for(i=0;i<g->n;i++) /*for(i=0;i<g->n;i++) /* 输入图中的顶点值输入图中的顶点值 */*/

g->vexs[i]=getchar();g->vexs[i]=getchar();

for(i=0;i<g->n;i++) /*for(i=0;i<g->n;i++) /* 初始化邻接矩阵初始化邻接矩阵 */*/

for(j=0;j<g->n;j++)for(j=0;j<g->n;j++)

g->edges[i][j]=INFINITY;g->edges[i][j]=INFINITY;

printf("please input edges:\n");printf("please input edges:\n");

for (k=0;k<g->e;k++) /*for (k=0;k<g->e;k++) /* 输入网络中的边输入网络中的边 */*/

{ { scanf("%d%d%d", &i,&j,&w);scanf("%d%d%d", &i,&j,&w);

g->edges[i][j]=w; g->edges[i][j]=w; }}

/*/* 若是建立无向网,只需在此加入语句若是建立无向网,只需在此加入语句 g->edges[j][i]=wg->edges[j][i]=w 即可即可 **//

} }

Page 34: 数据结构 第 7 章  图

数据结构 34

说明说明 ::当建立有向网时,边信息以三元组(当建立有向网时,边信息以三元组( ii ,, jj ,,ww)的形式输入,)的形式输入, ii 、、 jj 分别表示两顶点的序号,分别表示两顶点的序号,ww表示边上的权。对于每一条输入的边信息(表示边上的权。对于每一条输入的边信息( ii ,,jj ,, ww),只需将),只需将 g->edges[i][j]g->edges[i][j] 赋值为赋值为 ww。 。 当建立无向网时,对每一条输入的边信息(当建立无向网时,对每一条输入的边信息( ii ,,jj ,, ww)后,需同时将)后,需同时将 g->edges[i][j] g->edges[i][j] 和和 g->edg->edges[j][i]ges[j][i] 赋值为赋值为 ww。。当建立非网络的存储结构时,所有的边信息只当建立非网络的存储结构时,所有的边信息只需按二元组(需按二元组( ii ,, jj )的形式输入。 )的形式输入。

Page 35: 数据结构 第 7 章  图

数据结构 35

用邻接矩阵表示图时,某顶点的用邻接矩阵表示图时,某顶点的 "" 第一第一个个 "" 邻接点就应该是该顶点所对应的行中邻接点就应该是该顶点所对应的行中值为非零元素的最小列号,其值为非零元素的最小列号,其 "" 下一下一个个 "" 邻接点就是同行中离它最近的值为非邻接点就是同行中离它最近的值为非零元素的列号。零元素的列号。

Page 36: 数据结构 第 7 章  图

数据结构 36

2.2. 邻接表及其实现邻接表及其实现 用邻接矩阵表示法存储图时,占用的存储单元用邻接矩阵表示法存储图时,占用的存储单元个数只与图中顶点的个数有关,而与边的数目无关个数只与图中顶点的个数有关,而与边的数目无关。一个含有。一个含有 nn 个顶点的图,如果其边数比个顶点的图,如果其边数比 nn22少得少得多,那么它的邻接矩阵就会有很多空元素,浪费了多,那么它的邻接矩阵就会有很多空元素,浪费了存储空间。 存储空间。

无向图的邻接表无向图的邻接表 对于图对于图 GG 中的每个顶点中的每个顶点 vvii ,该方法把所有邻接于,该方法把所有邻接于vvii 的顶点的顶点 vvjj链成一个带头结点的单链表,这个单链表链成一个带头结点的单链表,这个单链表就称为顶点就称为顶点 vvii 的邻接表。单链表中的每个结点至少包的邻接表。单链表中的每个结点至少包含两个域,一个为含两个域,一个为邻接点域邻接点域(( adjvexadjvex ),它指示与顶),它指示与顶点点 vvii 邻接的顶点在图中的位序,另一个为邻接的顶点在图中的位序,另一个为链域链域(( nextnext),它指示与顶点),它指示与顶点 vvii 邻接的下一个结点。 邻接的下一个结点。

Page 37: 数据结构 第 7 章  图

数据结构 37

v0

v1 v3

v2

无向图无向图 GG99

1 2 3 ^

0 2 ^

0 1 3 ^

0 2 ^

V0

V1

V2

V3

GG99 的邻接表的邻接表

Page 38: 数据结构 第 7 章  图

数据结构 38

adjvex nextadjvex nextvertex firstdegevertex firstdege

表头结点表头结点结构结构

边结点结边结点结构构

#define MAX_VERTEX_NUM 20 /*#define MAX_VERTEX_NUM 20 /* 预定义图的最大顶点数预定义图的最大顶点数 */*/

typedef char datatype; /*typedef char datatype; /*顶点信息数据类型顶点信息数据类型 */*/

typedef struct node{ /*typedef struct node{ /*边表结点边表结点 */*/

int adjvex; /*int adjvex; /*邻接点邻接点 */*/

struct node *next;struct node *next;

}edgenode;}edgenode; adjvex nextadjvex next

边结点结边结点结构构

Page 39: 数据结构 第 7 章  图

数据结构 39

typedef struct vnode{ /*typedef struct vnode{ /*头结点类型头结点类型 */*/

datatype vertex; /*datatype vertex; /*顶点信息顶点信息 */*/

edgenode *firstedge; /*edgenode *firstedge; /*邻接链表头指针邻接链表头指针 */*/

}vertexnode;}vertexnode;

typedef struct{ /*typedef struct{ /*邻接表类型邻接表类型 */*/

vertexnode adjlist[MAX_VERTEX_NUM]; vertexnode adjlist[MAX_VERTEX_NUM];

/*/* 存放头结点的顺序表存放头结点的顺序表 */*/

int vexnum,arcnum; /*int vexnum,arcnum; /*图的顶点数与边数图的顶点数与边数 */*/

}adjgraph;}adjgraph;

vertex firstdegevertex firstdege

头结点结头结点结构构

Page 40: 数据结构 第 7 章  图

数据结构 40

对于无向图,对于无向图, vvii 的邻接表中每个表结点都对应于与的邻接表中每个表结点都对应于与vvii 相关联的一条边;相关联的一条边;

对于有向图来说,对于有向图来说,如果每一顶点如果每一顶点 vvii 的邻接表中每个表结点都存储以的邻接表中每个表结点都存储以vvii 的为始点射出的一条边,则称这种表为有向图的为始点射出的一条边,则称这种表为有向图的的出边表出边表(也称为有向图的邻接表)(也称为有向图的邻接表)反之,若每一顶点反之,若每一顶点 vvii 的邻接表中每个表结点都对的邻接表中每个表结点都对应于以应于以 vvii 为终点的边(即射入为终点的边(即射入 vvii 的边),则称这的边),则称这种表为有向图的种表为有向图的入边表入边表(又称逆邻接表)。 (又称逆邻接表)。

Page 41: 数据结构 第 7 章  图

数据结构 41

v0

v1

v2

v3

1 ^0 2

^0 1 ^

1 ^

GG1010 的出边表的出边表

v3

v1

v0 v2

有向图有向图 GG1010

v0

v1

v2

v3

1 2 ^

0 2

1 ^

3 ^

GG1010 的入边表的入边表

^

Page 42: 数据结构 第 7 章  图

数据结构 42

在无向图的邻接表中,顶点在无向图的邻接表中,顶点 vvii 的度为第的度为第 ii 个链表个链表中结点的个数;而在有向图的出边表中,第中结点的个数;而在有向图的出边表中,第 ii 个链表个链表中的结点个数是顶点中的结点个数是顶点 vvii 的出度;为了求入度,必须的出度;为了求入度,必须对整个邻接表扫描一遍,所有链表中其邻接点域的值对整个邻接表扫描一遍,所有链表中其邻接点域的值为为 ii 的结点的个数是顶点的结点的个数是顶点 vvii 的入度。 的入度。

1 2 3 ^

0 2 ^

0 1 3 ^

0 2 ^

V0

V1

V2

V3

VV00 的度为的度为 33v0

v1

v2

v3

1 ^0 2

^0 1 ^

1 ^

GG1010 的出边表的出边表

VV00 的出度为的出度为11 ,入度为,入度为 22

Page 43: 数据结构 第 7 章  图

数据结构 43

/* /* 无向图的邻接表创建算法 无向图的邻接表创建算法 */*/

void createadjgraph(adjgraph *g){ void createadjgraph(adjgraph *g){

int i,j,k;int i,j,k;

edgenode *s;edgenode *s;

printf("Please input n and e:\n");printf("Please input n and e:\n");

scanf("%d%d",&g->vexnum,&g->arcnum);scanf("%d%d",&g->vexnum,&g->arcnum);

printf("Please input %d vertex:",g->vexnum);printf("Please input %d vertex:",g->vexnum);

Page 44: 数据结构 第 7 章  图

数据结构 44

for(i=0;i<g->n;i++){for(i=0;i<g->n;i++){

scanf(“%c”,&g->adjlist[i].vertex);/*scanf(“%c”,&g->adjlist[i].vertex);/* 读入顶点信息读入顶点信息*/ */

g->adjlist[i].firstedge=NULL; /*g->adjlist[i].firstedge=NULL; /*边表置为空表边表置为空表 */*/

}}

printf("Please input %d edges:",g->e);printf("Please input %d edges:",g->e);

for(k=0;k<g->e;k++){ /*for(k=0;k<g->e;k++){ /* 循环循环 ee次建立边表次建立边表 */*/

scanf("%d%d",&i,&j); /*scanf("%d%d",&i,&j); /* 输入无序对(输入无序对( i,ji,j )) **//

s=(edgenode *)malloc(sizeof(edgenode));s=(edgenode *)malloc(sizeof(edgenode));

s->adjvex=j; /*s->adjvex=j; /*邻接点序号为邻接点序号为 j*/j*/

s->next=g->adjlist[i].firstedge;s->next=g->adjlist[i].firstedge;

g->adjlist[i].firstedge=s; g->adjlist[i].firstedge=s;

/*/*将新结点将新结点 *s*s 插入顶点插入顶点 vvii 的边表头部的边表头部 */*/

Page 45: 数据结构 第 7 章  图

数据结构 45

s=(edgenode *)malloc(sizeof(edgenode));s=(edgenode *)malloc(sizeof(edgenode));

s->adjvex=i; /*s->adjvex=i; /* 邻接点序号为邻接点序号为 i*i*//

s->next=g->adjlist[j].firstedge;s->next=g->adjlist[j].firstedge;

g->adjlist[j].firstedge=s; g->adjlist[j].firstedge=s;

/*/*将新结点将新结点 *s*s 插入顶点插入顶点 vvjj 的边表头部的边表头部 */*/

}}

}}

建立无向图的邻接表算法建立无向图的邻接表算法

Page 46: 数据结构 第 7 章  图

数据结构 46

3.3. 有向图的十字链表及其实现有向图的十字链表及其实现 虽然在有向图的邻接表和逆邻接表中分别可以虽然在有向图的邻接表和逆邻接表中分别可以找到从顶点出发的弧和指向顶点的弧,但对于同一找到从顶点出发的弧和指向顶点的弧,但对于同一个有向图需要用两个结构来表示它毕竟不方便,因个有向图需要用两个结构来表示它毕竟不方便,因此当应用问题中同时需要对这两种弧进行处理时就此当应用问题中同时需要对这两种弧进行处理时就需要采用十字链表来表示有向图。需要采用十字链表来表示有向图。

有向图的十字链表有向图的十字链表 在在十字链表中,对应于有向图的每一个顶点有一个十字链表中,对应于有向图的每一个顶点有一个结点,对应于每一条弧有一个结点。结点,对应于每一条弧有一个结点。

其中,其中, firstinfirstin 和和 firstoutfirstout 分别指向以该顶点为弧头或弧尾的分别指向以该顶点为弧头或弧尾的第一个弧结点;第一个弧结点; hlink/tlinkhlink/tlink分别指向弧头分别指向弧头 // 尾相同的下一条弧尾相同的下一条弧。。

tailvex headvex hlink tlinktailvex headvex hlink tlinkdata firstin firstoutdata firstin firstout

Page 47: 数据结构 第 7 章  图

数据结构 47

Page 48: 数据结构 第 7 章  图

数据结构 48

表头结点表头结点结构结构

弧结点结弧结点结构构

#define MAX_VERTEX_NUM 20 /*#define MAX_VERTEX_NUM 20 /* 预定义图的最大顶点数预定义图的最大顶点数 */*/

typedef char datatype; /*typedef char datatype; /*顶点信息数据类型顶点信息数据类型 */*/

typedef struct ArcBox{ /*typedef struct ArcBox{ /*弧表结点弧表结点 */*/

int tailvex, headvex; /*int tailvex, headvex; /*该弧的尾和头顶点的位置该弧的尾和头顶点的位置 */*/

struct ArcBoxstruct ArcBox *hlink,*tlink*hlink,*tlink;/*;/* 弧头(尾)相同的链域弧头(尾)相同的链域 **//

} ArcBox;} ArcBox;

tailvex headvex hlink tlinktailvex headvex hlink tlinkdata firstin firstoutdata firstin firstout

Page 49: 数据结构 第 7 章  图

数据结构 49

typedef struct vnode{ /*typedef struct vnode{ /*顶点类型顶点类型 */*/

datatype vertex; /*datatype vertex; /*顶点信息顶点信息 */*/

ArcBox *firstin,*firstout;ArcBox *firstin,*firstout;

/*/* 指向顶点的第一条入指向顶点的第一条入 //出弧出弧 */*/

}vertexnode;}vertexnode;

typedef struct{ /*typedef struct{ /* 十字链表类型十字链表类型 */*/

vertexnode xlist[MAX_VERTEX_NUM]; vertexnode xlist[MAX_VERTEX_NUM];

/*/* 存放头结点的顺序表存放头结点的顺序表 */*/

int vexnum,arcnum; /*int vexnum,arcnum; /*图的顶点数与边数图的顶点数与边数 */*/

}OLGraph;}OLGraph;

Page 50: 数据结构 第 7 章  图

数据结构 50

4. 邻接多重表 在邻接表中,每一条边在邻接表中,每一条边 (v(vii,v,vjj)) 有两个结点,分别有两个结点,分别在第在第 ii 和第和第 jj 个链表中,这给某些图的操作带来不个链表中,这给某些图的操作带来不便。例如在需要对被搜索过的边作记号或删除一条便。例如在需要对被搜索过的边作记号或删除一条边时,需要找到同一条边的两个结点。那么在进行边时,需要找到同一条边的两个结点。那么在进行此类操作时采用邻接多重表更为合适。此类操作时采用邻接多重表更为合适。

Page 51: 数据结构 第 7 章  图

数据结构 51

在邻接多重表中,每一条边只有一个边结点。为有关在邻接多重表中,每一条边只有一个边结点。为有关边的处理提供了方便。边的处理提供了方便。

边结点的结构边结点的结构

mark vexmark vexii link linkii vex vexjj link linkjj

其中,其中, mark mark 是记录是否处理过的标记;是记录是否处理过的标记; vexvexii

和和 vexvexjj 是依附于该边的两顶点位置。是依附于该边的两顶点位置。 linklinkii域是链接域是链接指针,指向下一条依附于顶点指针,指向下一条依附于顶点 vexvexii 的边;的边; linklinkjj 也是也是链接指针,指向下一条依附于顶点链接指针,指向下一条依附于顶点 vexvexjj 的边。需要时的边。需要时还可设置一个存放与该边相关的权值的域 还可设置一个存放与该边相关的权值的域 costcost 。。

Page 52: 数据结构 第 7 章  图

数据结构 52

顶点结点的结构顶点结点的结构

存储顶点信息的结点表以顺序表方式组织,存储顶点信息的结点表以顺序表方式组织,每一个顶点结点有两个数据成员:其中,每一个顶点结点有两个数据成员:其中, vertex vertex 存放与该顶点相关的信息,存放与该顶点相关的信息, firstedge firstedge 是指示第一是指示第一条依附于该顶点的边的指针。条依附于该顶点的边的指针。

在邻接多重表中在邻接多重表中 , , 所有依附于同一个顶点的边所有依附于同一个顶点的边都链接在同一个单链表中。都链接在同一个单链表中。

从顶点 从顶点 i i 出发出发 , , 可以循链找到所有依附于该可以循链找到所有依附于该顶点的边,也可以找到它的所有邻接顶点。顶点的边,也可以找到它的所有邻接顶点。

vertex firstedge firstedge

Page 53: 数据结构 第 7 章  图

数据结构 53

V0

V1 V3

V234

56 78 25

V0

V1

V2

V3

56 0 1 ^

34 0 2

78 0 ^ 3

25 2 ^ 3 ^

0

1

2

3

无向网络的邻接多重表示例无向网络的邻接多重表示例

Page 54: 数据结构 第 7 章  图

数据结构 54

表头结点表头结点结构结构

弧结点结弧结点结构构

#define MAX_VERTEX_NUM 20 /*#define MAX_VERTEX_NUM 20 /* 预定义图的最大顶点数预定义图的最大顶点数 */*/

typedef struct EBox{ /*typedef struct EBox{ /*边结点边结点 */*/

int markint mark

int ivex, jvex; /*int ivex, jvex; /*该边依附的两个顶点位置该边依附的两个顶点位置 */*/

struct EBoxstruct EBox *ilink,*jlink*ilink,*jlink;/*;/* 依附于此两顶点的下一条边依附于此两顶点的下一条边 **//

} EBox;} EBox;

vertex Firstedge Firstedge mark vexmark vexii link linkii vex vexjj link linkjj

Page 55: 数据结构 第 7 章  图

数据结构 55

typedef struct vexbox{ /*typedef struct vexbox{ /*顶点类型顶点类型 */*/

datatype vertex; /*datatype vertex; /*顶点信息顶点信息 */*/

EBox *firstedge;EBox *firstedge;

/*/* 指向第一条依附于该顶点的边指向第一条依附于该顶点的边 */*/

}vexbox;}vexbox;

typedef struct{ /*typedef struct{ /* 十字链表类型十字链表类型 */*/

vexbox adjmulist[MAX_VERTEX_NUM]; vexbox adjmulist[MAX_VERTEX_NUM];

int vexnum,arcnum; /*int vexnum,arcnum; /* 无向图的顶点数与边数无向图的顶点数与边数 **//

}AMLGraph;}AMLGraph;

Page 56: 数据结构 第 7 章  图

数据结构 56

图的遍历

在图中,访问部分顶点后,可能又沿着其他边回到已在图中,访问部分顶点后,可能又沿着其他边回到已被访问过的顶点。为保证每一个顶点只被访问一次,被访问过的顶点。为保证每一个顶点只被访问一次,必须对顶点进行标记,一般用一个辅助数组 必须对顶点进行标记,一般用一个辅助数组 visit[n]visit[n]作为对顶点的标记,当顶点作为对顶点的标记,当顶点 vvii未被访问,未被访问, visit[i]visit[i] 值值为为 00;当;当 vvii 已被访问,则已被访问,则 visit[i]visit[i] 值为值为 11 。。有两种遍历方法(它们对无向图,有向图都适用)有两种遍历方法(它们对无向图,有向图都适用)

深度优先遍历深度优先遍历 广度优先遍历广度优先遍历

图的遍历:从图的某顶点出发,访问图中所有顶点,图的遍历:从图的某顶点出发,访问图中所有顶点,并且每个顶点仅访问一次。并且每个顶点仅访问一次。

Page 57: 数据结构 第 7 章  图

数据结构 57

1. 1. 深度优先遍历深度优先遍历

从图中某顶点从图中某顶点 vv出发: 出发: 11 )访问顶点)访问顶点 vv ;;22 )依次从)依次从 vv 的未被访问的邻接点出发,继续对图进行的未被访问的邻接点出发,继续对图进行深度优先遍历;深度优先遍历;

Page 58: 数据结构 第 7 章  图

数据结构 58

对于给定的图对于给定的图 G=G= (( VV ,, EE ),首先将),首先将 VV 中每一中每一个顶点都标记为未被访问,然后,选取一个源点个顶点都标记为未被访问,然后,选取一个源点 vvVV ,,将将 vv 标记为已被访问,再递归地用深度优先搜索方法,标记为已被访问,再递归地用深度优先搜索方法,依次搜索依次搜索 vv 的所有邻接点的所有邻接点 ww 。若。若 ww 未曾访问过,则以未曾访问过,则以ww 为新的出发点继续进行深度优先遍历,如果从为新的出发点继续进行深度优先遍历,如果从 vv 出出发有路的顶点都已被访问过,则从发有路的顶点都已被访问过,则从 vv 的搜索过程结束。的搜索过程结束。此时,如果图中还有未被访问过的顶点(该图有多个此时,如果图中还有未被访问过的顶点(该图有多个连通分量或强连通分量),则再任选一个未被访问过连通分量或强连通分量),则再任选一个未被访问过的顶点,并从这个顶点开始做新的搜索。上述过程一的顶点,并从这个顶点开始做新的搜索。上述过程一直进行到直进行到 VV 中所有顶点都已被访问过为止。中所有顶点都已被访问过为止。

Page 59: 数据结构 第 7 章  图

数据结构 59

V0

V7

V6

V5

V4

V3

V2

V1

V0

V1

V3

V2

V7

V6 V5

V4

序列序列 11 ::V0,V1,V3,V7,V4,V2,V5,V6

深度优先遍历过程:深度优先遍历过程:

由于没有规定由于没有规定访问邻接点的顺序,访问邻接点的顺序,深度优先序列不是唯一的深度优先序列不是唯一的

序列序列 22 ::V0,V1,V4,V7,V3,V2,V5,V6

Page 60: 数据结构 第 7 章  图

数据结构 60

c0

c1

c3

c2

c4

c5

c0

c1

c3

c2

c4

c5

DFSDFS序列:序列: cc00 c c11 c c33 c c44 c c55 c c22

但是,当存储结构已确定的情况下,遍历的结果但是,当存储结构已确定的情况下,遍历的结果将是确定的。将是确定的。

Page 61: 数据结构 第 7 章  图

数据结构 61

深度优先遍历算法实现:深度优先遍历算法实现:

bool visited[MAX_VERTEX_NUM]; bool visited[MAX_VERTEX_NUM];

void DFSTraverse(Graph G) {void DFSTraverse(Graph G) { int v;int v; for (v=0; v<G.vexnum; ++v) for (v=0; v<G.vexnum; ++v) visited[v] = false; visited[v] = false; for (v=0; v<G.vexnum; ++v) for (v=0; v<G.vexnum; ++v) if (!visited[v]) DFS(G, v);if (!visited[v]) DFS(G, v);}}

Page 62: 数据结构 第 7 章  图

数据结构 62

void DFS(Graph G, int v) {void DFS(Graph G, int v) { // // 从第从第 vv 个顶点出发递归地深度优先遍历图个顶点出发递归地深度优先遍历图 GG 。。 int w;int w; visited[v] = true; visited[v] = true; printf(v); printf(v); for(w=FirstAdjVex(G, v); w>=0; w=Nextfor(w=FirstAdjVex(G, v); w>=0; w=NextAdjVex(G, v, w))AdjVex(G, v, w)) if (!visited[w]) DFS(G, w);if (!visited[w]) DFS(G, w);}}

Page 63: 数据结构 第 7 章  图

数据结构 63

2. 广度优先遍历

图中某未访问过的顶点图中某未访问过的顶点 vvii出发:出发:11 )访问顶点)访问顶点 vvii ;;22 )访问)访问 vvii 的所有未被访问的邻接点的所有未被访问的邻接点 ww11 ,w ,w2 2 , …w, …wkk ;;33 )依次从这些邻接点出发,访问它们的所有未被访问)依次从这些邻接点出发,访问它们的所有未被访问

的邻接点的邻接点 ; ; 依此类推,直到图中所有访问过的顶点依此类推,直到图中所有访问过的顶点的邻接点都被访问;的邻接点都被访问;

V0

V7

V6 V5 V4 V3

V2 V1

V0

V1

V3

V2

V7

V6 V5 V4

求图求图 GG 的以的以 VV00 起点的的广度起点的的广度优先序列优先序列

V0,V1,V2,V3,V4,V5,V6,V7V0,V1,V2,V3,V4,V5,V6,V7

Page 64: 数据结构 第 7 章  图

数据结构 64

从图中某顶点从图中某顶点 vvii出发:出发:11 )访问顶点)访问顶点 vvii ;(容易实现);(容易实现)22 )访问)访问 vvii 的所有未被访问的邻接点的所有未被访问的邻接点 ww11 ,w ,w2 2 , …w, …wkk ;; 33 )依次从这些邻接点(在步骤 )依次从这些邻接点(在步骤 22 )访问的顶点))访问的顶点)出发,访问它们的所有未被访问的邻接点出发,访问它们的所有未被访问的邻接点 ; ; 依此类依此类推,直到图中所有访问过的顶点的邻接点都被访问;推,直到图中所有访问过的顶点的邻接点都被访问;为实现 为实现 33 ),需要保存在步骤),需要保存在步骤 (2(2 )中访问的顶点,)中访问的顶点,而且访问这些顶点邻接点的顺序为:先保存的顶点,而且访问这些顶点邻接点的顺序为:先保存的顶点,其邻接点先被访问。其邻接点先被访问。

广度优先算法:广度优先算法:

在广度优先遍历算法中,在广度优先遍历算法中,需设置一队列需设置一队列 QQ,,保存已访问的顶点,保存已访问的顶点,并控制遍历顶点的顺序。并控制遍历顶点的顺序。

Page 65: 数据结构 第 7 章  图

数据结构 65

QUEUE

V0

V1

V2

V3

V4

V5

V6

V7

V1

V2

V3

V0

V4

V5

V6

V7

V0

V7

V6 V5 V4 V3

V2 V1

数据结构:数据结构:

11 )全局标志数组)全局标志数组

int visited[vexnum]; /*int visited[vexnum]; /*全局标志向量全局标志向量 */*/

22 )邻接表存储结构)邻接表存储结构

Page 66: 数据结构 第 7 章  图

数据结构 66

/*图的广度优先遍历算法 */

void BFSTraverse(Graph G, Status (*Visit)(int v )){void BFSTraverse(Graph G, Status (*Visit)(int v )){ // // 按广度优先遍历图按广度优先遍历图 GG 。。 for (v=0; v<G.vexnum; ++v) for (v=0; v<G.vexnum; ++v)

visited[v] = FALSE;visited[v] = FALSE; InitQueue(Q); // InitQueue(Q); // 置空的辅助队列置空的辅助队列QQ for (v=0; v<G.vexnum; ++v)for (v=0; v<G.vexnum; ++v) if (!visited[v]) { // vif (!visited[v]) { // v 尚未访尚未访问问 visited[v] = TRUE; Visit(v); // visited[v] = TRUE; Visit(v); // 访问访问 vv EnQueue(Q, v); // vEnQueue(Q, v); // v 入队列入队列

Page 67: 数据结构 第 7 章  图

数据结构 67

while (!QueueEmpty(Q)) {while (!QueueEmpty(Q)) { DeQueue(Q, u); // DeQueue(Q, u); // 队头元素出队并置为队头元素出队并置为 uu for (w=FirstAdjVex(G, u); w>=0; w=NextAfor (w=FirstAdjVex(G, u); w>=0; w=NextAdjVex(G, u, w))djVex(G, u, w))

if (!visited[w]) {if (!visited[w]) {visited[w] = TRUE; Visit(w);visited[w] = TRUE; Visit(w);

EnQueue(Q, w); EnQueue(Q, w); }//if }//if }//while }//while }//if}//if} // BFSTraverse} // BFSTraverse

Page 68: 数据结构 第 7 章  图

数据结构 68

假设图假设图 G=(V,E)G=(V,E) ,其中,其中 VV 是顶点的集合,是顶点的集合, EE 是边是边(( 或弧或弧 )) 的集合。则在对图进行遍历的过程中,将的集合。则在对图进行遍历的过程中,将边分成两个集合边分成两个集合 T(E)T(E) 和和 B(E)B(E) ,其中,其中 T(E)T(E) 中的边中的边具有这样的特性:通过它找到 “未被访问” 的邻具有这样的特性:通过它找到 “未被访问” 的邻接点,并称这些边为接点,并称这些边为 ""树边树边 "";其余的边均为集合;其余的边均为集合B(E)B(E) 中的边,称这些边为中的边,称这些边为 "" 回边回边 ""。。

Page 69: 数据结构 第 7 章  图

数据结构 69

生成树生成树:对于一个无向的连通图生成树:对于一个无向的连通图 G=G= (( VV ,, EE ),),设设 G‘G‘是它的一个子图,如果是它的一个子图,如果 G’G’中包含了中包含了 GG 中所中所有的顶点(即有的顶点(即 VV (( G‘G‘)) =V=V (( GG ))且只有))且只有 n-1n-1 条条边,则称边,则称 G'G'为为 GG 一棵的生成树。 一棵的生成树。

生成树有许多重要的应用。令图 G的顶点表示城市,边表示连接两个城市之间的通讯线路,则把 n 个城市连接起来至少要有 n-1 条线路,而图G的生成树表示了建立通讯网络的可行方案。深度优先生成树:按深度优先遍历生成的生成树深度优先生成树:按深度优先遍历生成的生成树

广度优先生成树:按广度优先遍历生成的生成广度优先生成树:按广度优先遍历生成的生成树树

Page 70: 数据结构 第 7 章  图

数据结构 70

有向图的生成树有向图的生成树

c0

c1 c3c2 c4

c5 c6

c0

c1 c3c2 c4

c5 c6

c0

c1 c3c2 c4

c5 c6

(( aa )以)以 cc00 为根的有向图 (为根的有向图 ( bb )) DFSDFS生成树 (生成树 ( cc )) BFSBFS生成树生成树

Page 71: 数据结构 第 7 章  图

数据结构 71

非连通图的生成森林非连通图的生成森林

V0 V1

V3 V4

V2 V6

V8

V7

V5

V9

V0

V1

V3V4

V2

V6V8

V7V5

V9

V0 V1

V3 V4

V2

V8

V7

V9

V6

V5

(( aa )不连通的无向图)不连通的无向图 GG1212 (( bb )图)图 GG1212 的一个的一个 DFSDFS生成生成森林 森林

(( cc )图)图 GG1212 的一个的一个 BFSBFS生成森林生成森林

Page 72: 数据结构 第 7 章  图

数据结构 72

图的深度优先生成森林算法实现(以孩子兄弟法表示法表示森林)void DFSForest(Graph G, CSTree &T) { T = NULL;

for (v=0; v<G.vexnum; ++v) visited[v] = FALSE; for (v=0; v<G.vexnum; ++v) if (!visited[v]) { p= (CSTree)malloc(sizeof(CSNode)); p->data=GetVex(G,v); p->firstchild=NULL; p->nextsibling=NULL; if (!T) T = p; else q->nextsibling = p; q = p; DFSTree(G, v,p); // 建立以 p为根的生成树 }//if} // DFSForest

Page 73: 数据结构 第 7 章  图

数据结构 73

void DFSTree(Graph G, int v, CSTree &T) { bool first =TRUE; visited[v] = TRUE;

for(w=FirstAdjVex(G,v); w!=-1;w=NextAdjVex(G,v,w)) if (!visited[w]) { p = (CSTree) malloc (sizeof(CSNode));

p->data = GetVex(G,w); p->firstchild=NULL; p->nextsibling=NULL; if (first) { // w是 v的第一个未被访问的邻接顶点 T->firstchild = p;

first = FALSE; // 是根的左孩子结点 } else { // w是 v的其它未被访问的邻接顶点 q->nextsibling = p; } q = p; DFSTree(G,w,q) ; }//if} // DFSTree

Page 74: 数据结构 第 7 章  图

数据结构 74

扩展习题 数据结构

容易:1182, 1656, 2021, 2023, 2051, 2153, 2227, 2236, 2247, 2352, 2395, 不易:1145, 1177, 1195, 1227, 1661, 1834, 推荐:1330, 1338, 1451, 1470, 1634, 1689, 1693, 1703, 1724, 1988, 2004, 2010, 2119, 2274,

图论 容易:1161, 1164, 1258, 1175, 1308, 1364, 1776, 1789, 1861, 1939, 1940, 1943, 2075, 2139, 2387, 2394, 2421, 不易:1041, 1062, 1158, 1172, 1201, 1275, 1718, 1734, 1751, 1904, 1932, 2173, 2175, 2296,

Page 75: 数据结构 第 7 章  图

数据结构 75

最小生成树 使用不同的遍历图的方法,可以得到不同使用不同的遍历图的方法,可以得到不同的生成树;从不同的顶点出发,也可能得的生成树;从不同的顶点出发,也可能得到不同的生成树。到不同的生成树。

对于连通网络 G = (V , E) ,边是带权的,因而 G的生成树的各边也是带权的。我们把生成树各边的权值总和称为生成树的权,并把权最小的生成树称为 G的最小生成树(Minimun Spanning Tree) 。

Page 76: 数据结构 第 7 章  图

数据结构 76

Page 77: 数据结构 第 7 章  图

数据结构 77

例:要在 例:要在 n n 个城市间建立个城市间建立交通网,要考虑的问题如何交通网,要考虑的问题如何在保证 在保证 n n 点连通的前题下点连通的前题下最节省经费最节省经费 ? ?

),(

)(Evu

uvwTW

A

B

C D

E F

10

10

1512

12 87

6

6

5

上述问题即要使得生成树各上述问题即要使得生成树各边权值之各最小,即:边权值之各最小,即:

Page 78: 数据结构 第 7 章  图

数据结构 78

构造最小生成树的准则:构造最小生成树的准则:必须只使用该网络中的边来构造最小生成树;必须只使用该网络中的边来构造最小生成树;必须使用且仅使用必须使用且仅使用 n-1n-1 条边来联接网络中的条边来联接网络中的 nn 个顶点;个顶点;不能使用产生回路的边。 不能使用产生回路的边。

假设假设 G=G= (( VV ,, EE )是一个连通网,)是一个连通网, UU是顶点集是顶点集 VV 的一的一个非空真子集,若(个非空真子集,若( uu,, vv )是满足)是满足 uuUU,, vvV-UV-U的的边且(边且( uu,, vv )在所有的两栖边(两顶点分别在)在所有的两栖边(两顶点分别在 UU及及V-UV-U中的边)中具有最小的权值,则必存在一棵包含边中的边)中具有最小的权值,则必存在一棵包含边(( uu,, vv )的最小生成树。)的最小生成树。

MSTMST性质:性质:

(Prim)(Prim) 算法和算法和 (Kruskal)(Kruskal) 算法是两个利用算法是两个利用 MSTMST性质性质构造最小生成树的算法。构造最小生成树的算法。

Page 79: 数据结构 第 7 章  图

数据结构 79

普里姆 (Prim) 算法 普里姆算法的基本思想:普里姆算法的基本思想:

从连通网络 从连通网络 G = { V, E }G = { V, E } 中的某一顶点 中的某一顶点 uu0 0 出出发,选择与它关联的具有最小权值的边发,选择与它关联的具有最小权值的边 (u(u00, v), v) ,将,将其顶点加入到生成树的顶点集合其顶点加入到生成树的顶点集合 UU中。中。 以后每一步从一个顶点在以后每一步从一个顶点在 UU中,而另一个顶点不中,而另一个顶点不在在 UU中的各条边中选择权值最小的边中的各条边中选择权值最小的边 (u, v),(u, v), 把它的把它的顶点加入到集合顶点加入到集合 UU中。如此继续下去,直到网络中的中。如此继续下去,直到网络中的所有顶点都加入到生成树顶点集合所有顶点都加入到生成树顶点集合 UU中为止。中为止。

Page 80: 数据结构 第 7 章  图

数据结构 80

PrimPrim算法的基本步骤如下:算法的基本步骤如下:

(( 11 )初始化:)初始化: U={uU={u00}} ,, TREE={};TREE={};

(( 22 )如果)如果 U=VU=V (( GG ),则输出最小生成树),则输出最小生成树 TT ,并,并结束算法;结束算法;

(( 33 )在所有两栖边(两顶点分别在)在所有两栖边(两顶点分别在 UU 及及 V-UV-U 中的中的边)中找一条权最小的边(边)中找一条权最小的边( uu ,, vv )(若候选两栖)(若候选两栖边中的最小边不止一条,可任选其中的一条),将边中的最小边不止一条,可任选其中的一条),将边(边( uu ,, vv )加入到边集)加入到边集 TREETREE 中,并将顶点中,并将顶点 vv 并入并入集合集合 UU中。中。

(( 44 )由于新顶点的加入,)由于新顶点的加入, UU 的状态发生变化,需的状态发生变化,需要对要对 UU与与 V-UV-U之间的两栖边进行调整。之间的两栖边进行调整。

(( 55 )转步骤()转步骤( 22 ))

Page 81: 数据结构 第 7 章  图

数据结构 81

对于步骤,对于步骤,(( 44 )由于新顶点的加入,)由于新顶点的加入, UU的状态发生变化,需要对的状态发生变化,需要对UU与与 V-UV-U之间的两栖边进行调整。之间的两栖边进行调整。

这是因为每个顶点都是通过“一条边”加入到生成树上的,欲找最小生成树,则只保留一条权值最小的边即可。

在对两栖边进行调整时,对集合 在对两栖边进行调整时,对集合 V-U V-U 中的每个顶点,中的每个顶点,当它和集合 当它和集合 U U 中的顶点有一条以上的边相连时,只中的顶点有一条以上的边相连时,只需要保留一条权值最小的边即可需要保留一条权值最小的边即可 。

Page 82: 数据结构 第 7 章  图

数据结构 82

AB

C D

E F

10

10

1512

12 87

6

6

5

(( aa )无向)无向网网

5

AB

C D

E F

10

7 6

10

(( ee )选取()选取( BB 、、FF ))

AB

C D

E F

10

1512

(( bb )初始状态)初始状态

5

AB

C D

E F

10

15 7 6

(( cc )选取()选取( AA 、、BB ))

5

AB

C D

E F

10

15 7 6

(( dd ))选取(选取( BB、、DD) )

5

AB

C D

E F

10

7 6

10

(( ff )选取()选取( BB 、、 CC ))

5

AB

C D

E F

10

7 6

10

(( gg )选取()选取( EE 、、 FF ))

Page 83: 数据结构 第 7 章  图

数据结构 83

PrimPrim算法实现:算法实现:

11 、连通图用邻接矩阵、连通图用邻接矩阵 netnet 表示:表示:

edges[i][j]=edges[i][j]=WWij ij 当(当( vi,vjvi,vj ) ) EE (( GG )且权为)且权为WWijij否则 否则

22 、最小代价边、最小代价边 closedge[MAX_VERTEX_NUM-1]closedge[MAX_VERTEX_NUM-1]

struct { struct {

VertexType adjvex; VertexType adjvex;

VPType lowcost; VPType lowcost;

} closedge[MAX_VERTEX_NUM-1];} closedge[MAX_VERTEX_NUM-1];

Page 84: 数据结构 第 7 章  图

数据结构 84

void MiniSpanTree_PRIM( MGraph G,VertexType u){   k = LocateVex ( G, u );   for ( j=0; j<G.vexnum; ++j )    if (j!=k)closedge[j]={u,G.arcs[k][j].adj};     closedge[k].lowcost = 0;   

   for (i=1; i<G.vexnum; ++i) {       k = minimum(closedge);        print(closedge[k].adjvex,G.vex[k]) ;

closedge[k].lowcost = 0;// 第 k 顶点并入U集    for (j=0; j<G.vexnum; ++j)     if (G.arcs[k][j].adj < closedge[j].lowcost)       closedge[j]={G.vexs[k],G.arcs[k][j].adj };    } // for  } // MiniSpanTree

Page 85: 数据结构 第 7 章  图

数据结构 85

克鲁斯卡尔算法KruskalKruskal 算法基本思想:算法基本思想:

为使生成树上边的权值之和最小,显然,其为使生成树上边的权值之和最小,显然,其中每一条边的权值应该尽可能地小。克鲁斯卡尔算中每一条边的权值应该尽可能地小。克鲁斯卡尔算法的做法就是:先构造一个只含法的做法就是:先构造一个只含 nn 个顶点的子图个顶点的子图 SGSG,然后从权值最小的边开始,若它的添加不使,然后从权值最小的边开始,若它的添加不使 SGSG中产生回路,则在中产生回路,则在 SGSG 上加上这条边,如此重复,上加上这条边,如此重复,直至加上直至加上 n-1n-1 条边为止。条边为止。

Page 86: 数据结构 第 7 章  图

数据结构 86

算法:算法:

1) 1) 对边集 对边集 E E 按每个边的权值大小进行升序排列。按每个边的权值大小进行升序排列。2) 2) 初始化最小花费生成树的边集 初始化最小花费生成树的边集 T T 为空。为空。3) 3) 把图的每个顶点都初始化为树的根节点。把图的每个顶点都初始化为树的根节点。4) 4) 取出当前边集 取出当前边集 E E 中最小权值的边,假设边 中最小权值的边,假设边 e=(u,e=(u,v) v) ,如果当前边连接的两个节点 ,如果当前边连接的两个节点 u u 和 节点 和 节点 v v 不不在同一棵树中,则把两个节点所在的树合并在一起,成在同一棵树中,则把两个节点所在的树合并在一起,成为同一棵树。同时从边集 为同一棵树。同时从边集 E E 中删除边 中删除边 e e 并且把边 并且把边 e e 加入到最小花费生成树的边集 加入到最小花费生成树的边集 T T 中。中。5) 5) 重复步骤 重复步骤 (4) (4) ,直到边集 ,直到边集 T T 中的边数为 中的边数为 n-1 n-1 。。( n ( n 为图 为图 G G 中节点的总个数 中节点的总个数 ))

Page 87: 数据结构 第 7 章  图

数据结构 87

vv00

vv11

vv22

vv33

vv44 vv55

66 55

1155 55

44 223366

66

(a) (a) 无向网络图无向网络图

KruskalKruskal 算法动态演示:算法动态演示:

1155

44 2233

vv00

vv11

vv22

vv33

vv44 vv55

(b) (b) 最小生成树求解过程最小生成树求解过程

Page 88: 数据结构 第 7 章  图

数据结构 88

void kruskal(MGraph G){ int set[MAX_VERTEX_NUM],i,j; int k=0,a=0,b=0,min=G.arcs[a][b]; for(i=0;i<G.vexnum;i++) set[i]=i; printf("最小生成树的各条边为 :\n"); while(k<G.vexnum-1){ for(i=0;i<G.vexnum;++i) for(j=i+1;j<G.vexnum;++j) if(G.arcs[i][j]<min){

min=G.arcs[i][j]; a=i; b=j; }

min=G.arcs[a][b]=5000; if(set[a]!=set[b]){ printf("%s-%s\n",G.vexs[a],G.vexs[b]); k++; for(i=0;i<G.vexnum;i++) if(set[i]==set[b]) set[i]=set[a]; } } }

Page 89: 数据结构 第 7 章  图

数据结构 89

最短路径问题的提出:问题的提出: 交通咨询系统、通讯网、计算机网络常要寻找两结交通咨询系统、通讯网、计算机网络常要寻找两结点间最短路径;点间最短路径;

交通咨询系统:交通咨询系统: A A 到 到 B B 最短路径;最短路径;计算机网络计算机网络 :: 发送发送 EmailEmail 节省费用 节省费用 AA 到到 BB 沿最沿最短路径传送;短路径传送;

路径长度:路径长度:路径上边数路径上边数路径上边的权值之和路径上边的权值之和

最短路径:两结点间权值之和最小的路径;最短路径:两结点间权值之和最小的路径;

Page 90: 数据结构 第 7 章  图

数据结构 90

A

B

D

CF

E2

4

1528

8

18

10

13

始点 终点 最短路径 路径长度

A B ( A , C , B ) 19

C ( A , C ) 4

D ( A , C , F , D ) 25

E ( A , C , B , E ) 29

F ( A , C , F ) 12

4

如何求的从如何求的从 AA

到到 DD 的最短路径为的最短路径为 2525

2525 而不是而不是 2828 ??

Page 91: 数据结构 第 7 章  图

数据结构 91

介绍求最短路径的两个算法 介绍求最短路径的两个算法 求从某个源点到其他各顶点的最短路径(单求从某个源点到其他各顶点的最短路径(单源最短路径)。源最短路径)。求每一对顶点之间的最短路径。求每一对顶点之间的最短路径。

Page 92: 数据结构 第 7 章  图

数据结构 92

单源最短路径单源最短路径问题是指:对于给定的有向单源最短路径问题是指:对于给定的有向网网 G=G= (( VV ,, EE ),求源点),求源点 vv00 到其它顶点的到其它顶点的最短路径。最短路径。Dijkstra (Dijkstra ( 迪杰斯特拉迪杰斯特拉 )) 提出了一个按路提出了一个按路径长度递增的顺序逐步产生最短路径的方法,径长度递增的顺序逐步产生最短路径的方法,称为称为 DijkstraDijkstra 算法。 算法。 Dijkstra Dijkstra 法首先求出长度最短的一条最短法首先求出长度最短的一条最短路径,再参照它求出长度次短的一条最短路路径,再参照它求出长度次短的一条最短路径,依次类推,直到从顶点径,依次类推,直到从顶点 vv 到其它各顶点到其它各顶点的最短路径全部求出为止。的最短路径全部求出为止。(每个点都仅以两种方(每个点都仅以两种方式与源点相连)式与源点相连)

Page 93: 数据结构 第 7 章  图

数据结构 93

DijkstraDijkstra逐步求解的过程逐步求解的过程

源点 终点 最 短 路 径 路径长度 v0 v1 (v0, v1) 10

v2 — (v0, v1, v2) (v0, v3, v2) — 60 50 v3 (v0, v3) 30 v4 (v0, v4) (v0, v3, v4) (v0, v3, v2, v4) 100 90 60

Page 94: 数据结构 第 7 章  图

数据结构 94

为了实现上述过程,引入一个辅助数组为了实现上述过程,引入一个辅助数组 d[]d[]。它的每。它的每一个分量一个分量 d[i]d[i]表示当前找到的从源点表示当前找到的从源点 vv00 到顶点到顶点 vvii 的的最短路径的长度。初始状态:最短路径的长度。初始状态:–若从源点若从源点 vv00 到顶点到顶点 vvii 有边,则有边,则 d[i]d[i]为该边上的权为该边上的权值值

–若从源点若从源点 vv00 到顶点到顶点 vvii 没有边,则没有边,则 d[i]d[i]为为 ++ 。。 一般情况下,假设 一般情况下,假设 S S 是已求得的最短路径的终点的是已求得的最短路径的终点的

集合,则可证明:下一条最短路径必然是从集合,则可证明:下一条最短路径必然是从 vv0 0 出发,出发,中间只经过中间只经过 SS中的顶点便可到达的那些顶点中的顶点便可到达的那些顶点 vvxx (v (vxx VV-S )-S ) 的路径中的一条,或者是弧的路径中的一条,或者是弧 <v<v00 ,vvxx> 。。

每次求得一条最短路径之后,其终点每次求得一条最短路径之后,其终点 vvk k 加入集合加入集合 SS,,然后对所有的然后对所有的 vvii V-SV-S,修改其,修改其 d[i]d[i] 值。值。

Page 95: 数据结构 第 7 章  图

数据结构 95

DijkstraDijkstra 算法可描述如下:算法可描述如下:1)初始化:1)初始化: S ← { v0 };S ← { v0 }; d[j] ← g.edges[vd[j] ← g.edges[v00][j], j = 1, 2, …, ][j], j = 1, 2, …,

n-1;n-1; 2) 求出2) 求出 SS与与 V-SV-S间的最短路径,及相应的点间的最短路径,及相应的点 vv d[v] ← min{ d[i] }, i d[v] ← min{ d[i] }, i V V (( GG )) - S - S ; ; S ← S U { vS ← S U { v };};3)由于3)由于 vv 的加入,修改的加入,修改 SS中各结点与中各结点与 SS中各点的最中各点的最短距离: 短距离: d[i] ← min{ d[i], d[v] + edges[v][i] },d[i] ← min{ d[i], d[v] + edges[v][i] },   对于每一个    对于每一个 i i V- S ; V- S ;

4)判断: 若4)判断: 若 S = V, S = V, 则算法结束,否则转2)则算法结束,否则转2)。。

Page 96: 数据结构 第 7 章  图

数据结构 96

void ShortestPath_DIJ( MGraph G,int v0, PATH p, int d[]){  for( v=0;v<G.vexnum;++v){  

  final[v] = FALSE; d[v] = G.arcs[v0][v];   for( w=0;w<G.vexnum;++w)p[v][w] = false;    if(dist[v]<INFINITY){

p[v][v0]=TRUE; P[v][v]=TRUE; }  } // for  d[v0] = 0; final[v0] = TRUE;   

Page 97: 数据结构 第 7 章  图

数据结构 97

for (i=1; i<G.vexnum; ++i){    min = INFINITY;   for (k=0; k<G.vexnum; ++k)      if (!final[k] && (d[k]<min)) {      v = k; min = d[k];

} final[v] = TRUE;

for (k=0; k<G.vexnum; ++k) if(!final[k]&&(min+G.arcs[v][k]<d[k]){

      d[k] = min + G.arcs[v][k];     p[k] = p[v];

p[k][k] = TRUE;     } // if  } // for i

} // ShortestPath_DIJ

Page 98: 数据结构 第 7 章  图

数据结构 98

所有顶点对的最短路径 问题的提法:已知一个各边权值均大于问题的提法:已知一个各边权值均大于 00 的带权有的带权有

向图,对每一对顶点 向图,对每一对顶点 vi vi vj vj ,要求求出,要求求出 vi vi 与与vjvj 之间的最短路径及其长度。之间的最短路径及其长度。

解决这个问题显然可以利用单源最短路径算法解决这个问题显然可以利用单源最短路径算法,具体做法是依次把有向网,具体做法是依次把有向网 GG 中的每个顶点作为源中的每个顶点作为源点,重复执行点,重复执行 DijkstraDijkstra 算法算法 nn 次,即执行循环体:次,即执行循环体:总的时间复杂度为总的时间复杂度为 O(nO(n33)) 。。

for for (( v=0v=0;; v<g.nv<g.n ;; v++v++))

{ { ShortestPath_DIJ (( gg,, vv ,, pp ,, dd ););

print_gpdprint_gpd (( gg,, pp ,, dd ););

}}

Page 99: 数据结构 第 7 章  图

数据结构 99

弗洛伊德( Floyd )算法 算法的基本思想是算法的基本思想是 :: 设置一个设置一个 NxNNxN的矩阵的矩阵 D[N][N]D[N][N] ,元素,元素 A[i][j]A[i][j]的值表示顶点的值表示顶点 vvii 到顶点到顶点 vvjj 的最短路径长度。那么的最短路径长度。那么可以通过递推构造一个矩阵序列可以通过递推构造一个矩阵序列 DD(-1)(-1),D,D(0)(0),…,D,…,D(n-1)(n-1)

来求每对顶点之间的最短路径。其中,来求每对顶点之间的最短路径。其中, DD(k)(k)[i][j][i][j](0<=k<n)(0<=k<n) 表示从顶点表示从顶点 vvii 到顶点到顶点 vvjj 的路径上所经过的路径上所经过的顶点序号不大于的顶点序号不大于 kk的最短路径。的最短路径。

运算步骤为:运算步骤为:初始时,初始时, DD(-1)(-1)[i][j]=edges[i][j][i][j]=edges[i][j]。。

Page 100: 数据结构 第 7 章  图

数据结构 100

当已经求出当已经求出 DD(k)(k) ,要递推求解的,要递推求解的 DD(k+1)(k+1) (即要递推求解(即要递推求解从顶点从顶点 vvii 到顶点到顶点 vvjj 的路径上所经过的顶点序号不大的路径上所经过的顶点序号不大于于 k+1k+1 的最短路径)的最短路径)时,时,可分两种情况来考虑:可分两种情况来考虑:

另一种情况是,该路径经过顶点序号为另一种情况是,该路径经过顶点序号为 k+1k+1 的顶点,的顶点,可分为两段,一段是从顶点可分为两段,一段是从顶点 vvii 到顶点到顶点 vvk+1k+1 的最短路径,的最短路径,另一段是从顶点另一段是从顶点 vvk+1k+1 到顶点到顶点 vvjj 的最短路径,则此时的的最短路径,则此时的最短路径长度等于这两段的最短路径长度之和。最短路径长度等于这两段的最短路径长度之和。

一种情况是,该路径不经过顶点序号为一种情况是,该路径不经过顶点序号为 k+1k+1 的顶点,的顶点,此时此时 DD(k+1)(k+1)[i][j][i][j]==DD(k)(k)[i][j][i][j];;

这两种情况中的路径长度较小者就是要求的从顶点这两种情况中的路径长度较小者就是要求的从顶点 vvii 到顶点到顶点 vvjj 的路径上所经过的顶点序号不大于的路径上所经过的顶点序号不大于 k+1k+1 的的最短路径最短路径 DD(k+1)(k+1)[i][j][i][j]。。

Page 101: 数据结构 第 7 章  图

数据结构 101

因此,弗洛伊德算法可以描述为因此,弗洛伊德算法可以描述为 ::

AA(-1)(-1)[i][j]=edges[i][j]; /*edges[i][j]=edges[i][j]; /*edges为图的邻接矩阵为图的邻接矩阵 */*/

AA(k)(k)[i][j]=min{A[i][j]=min{Ak-1k-1[i][j], A[i][j], Ak-1k-1[i][k]+A[i][k]+Ak-1k-1[k][j]}[k][j]}

其中 其中 k=0,1,2,…, n-1k=0,1,2,…, n-1

Page 102: 数据结构 第 7 章  图

数据结构 102

FloydFloyd 的算法实现的算法实现 ::

void floyd1(mgraph g,path p,dist d)void floyd1(mgraph g,path p,dist d)

{ int i,j,k;{ int i,j,k;

for(v=0;v<g.vexnum;v++) /*for(v=0;v<g.vexnum;v++) /* 初始化初始化 */*/

for(w=0;w<g.vexnum;w++)for(w=0;w<g.vexnum;w++)

{ d[v][w]=g.edges[v][w];{ d[v][w]=g.edges[v][w];

for(u=0;u<g.vexnum;u++)P[v][w][u]=FALSE;for(u=0;u<g.vexnum;u++)P[v][w][u]=FALSE; if(d[v][w]<INFINITY){if(d[v][w]<INFINITY){

p[v][w][v]=TRUE;p[v][w][v]=TRUE; p[v][w][w]=TRUE;p[v][w][w]=TRUE;

}} }}

Page 103: 数据结构 第 7 章  图

数据结构 103

for(u=0;u<g.vexnum;ufor(u=0;u<g.vexnum;u++) /*++) /* 递推求解每一对顶点间的最短距离递推求解每一对顶点间的最短距离 */*/

for(v=0;v<g.vexnum;v++)for(v=0;v<g.vexnum;v++)

for(w=0;w<g.vexnum;w++)for(w=0;w<g.vexnum;w++)

if (d[v][w]>(d[v][u]+d[u][w]))if (d[v][w]>(d[v][u]+d[u][w]))

{ d[v][w]=d[v][u]+d[u][w];{ d[v][w]=d[v][u]+d[u][w];

for(i=0;i<g.vexnum;i++)for(i=0;i<g.vexnum;i++)

p[v][w][i]=p[v][u][i]||p[w][u][i];p[v][w][i]=p[v][u][i]||p[w][u][i];

}}

}}

Page 104: 数据结构 第 7 章  图

数据结构 104

例: P191

Page 105: 数据结构 第 7 章  图

数据结构 105

拓扑排序拓扑排序是有向图的一个重要应用,它将有向图中顶点间的相互指向关系与某一序列对应起来。其对应关系为,若在有向图 G中从顶点 vi 到顶点 vj

有一条路径,则在序列中顶点 vi 必在顶点 vj 之前。满足这种对应关系的序列为一个拓扑序列。求一个有向图拓扑序列的过程称为拓扑排序。拓扑排序经常用于安排某一工程的子工程的执行顺序。此时通常先画出工程的工程流图(工程流图显然为一有向图),然后由这个工程流图得出其拓扑序列,此拓扑序列即对应了各子工程的执行顺序。

Page 106: 数据结构 第 7 章  图

数据结构 106

诸如工程流图等以顶点表示活动,以边表示诸如工程流图等以顶点表示活动,以边表示活动的顺序关系的有向图称为顶点表示活动活动的顺序关系的有向图称为顶点表示活动的网(的网( Activity On Vertex NetworkActivity On Vertex Network ),简),简称称 AOVAOV 网网。。

Page 107: 数据结构 第 7 章  图

数据结构 107

CC11 高等数学高等数学 CC22 程序设计基础程序设计基础 CC33 离散数学 离散数学 CC11, C, C22

CC44 数据结构 数据结构 CC33, C, C22

CC55 高级语言程序设计 高级语言程序设计 CC22

CC66 编译方法 编译方法 CC55, C, C44

CC77 操作系统 操作系统 CC44, C, C99

CC88 普通物理 普通物理 CC11

CC99 计算机原理 计算机原理 CC88

Page 108: 数据结构 第 7 章  图

数据结构 108

学生课程学习工程图两个可行的学习计划为:两个可行的学习计划为:

CC00CC11CC22CC44CC77CC88CC33CC66CC5 5 和和

CC11CC00CC77CC88CC22CC44CC33CC55CC66

Page 109: 数据结构 第 7 章  图

数据结构 109

1) 1) 输入输入 AOVAOV网络。令 网络。令 n n 为顶点个数。为顶点个数。2) 2) 在在 AOVAOV网络中选一个没有直接前驱(入度为网络中选一个没有直接前驱(入度为 00)的顶点)的顶点 , , 并输出之并输出之 ; ;

3) 3) 从图中删去该顶点从图中删去该顶点 , , 同时删去所有它发出的有同时删去所有它发出的有向边向边 ;;

4) 4) 重复以上重复以上 (2)(2) 、、 (3)(3)步步 , , 直到直到–全部顶点均已输出,拓扑有序序列形成,拓扑全部顶点均已输出,拓扑有序序列形成,拓扑排序完成;或排序完成;或

–图中还有未输出的顶点,但已跳出处理循环。图中还有未输出的顶点,但已跳出处理循环。这说明图中还剩下一些顶点,它们都有直接前这说明图中还剩下一些顶点,它们都有直接前驱,再也找不到没有前驱的顶点了。这时驱,再也找不到没有前驱的顶点了。这时 AOVAOV网络中必定存在有向环。网络中必定存在有向环。

拓扑排序过程拓扑排序过程

Page 110: 数据结构 第 7 章  图

数据结构 110

C0 C1 C2

C3 C4 C5

(a) (a) 有向无环图有向无环图

C1 C2

C5C3

(c) (c) 输出顶点输出顶点 C0C0

C0 C2

C5

C1

C3

(d) (d) 输出顶点输出顶点 C3C3

C0 C1 C2

C3 C4 C5

(b) (b) 输出输出 C4C4

Page 111: 数据结构 第 7 章  图

数据结构 111

C1 C2

C5

(e) (e) 输出顶点输出顶点 C2C2

C5

C1

(f) (f) 输出顶点输出顶点 C1C1

C5

(g) (g) 输出顶点输出顶点 C5C5

最后得到的拓扑有序序列为 最后得到的拓扑有序序列为 CC44 , C , C00 , C , C33 , C , C22 , C , C1 1 , C, C55 。它满足图中给出的所有前驱和后继关系,。它满足图中给出的所有前驱和后继关系,对于本来没有这种关系的顶点,如对于本来没有这种关系的顶点,如 CC44 和和 CC22 ,也排出,也排出了先后次序关系。了先后次序关系。

(h) (h) 拓扑排序完成拓扑排序完成

Page 112: 数据结构 第 7 章  图

数据结构 112

拓扑排序的实现拓扑排序的实现AOVAOV网络及其邻接表表示网络及其邻接表表示

C0

C1

C2

C3 0

C4

C5 0

0

1

2

3

4

5

id data firstedgeid data firstedge 1

3

0

1

0

3

1 adjvex nxetadjvex nxet

3 0 5 1 5 0

0 1 5 0C0 C1 C2

C3 C4 C5

Page 113: 数据结构 第 7 章  图

数据结构 113

这种带入度的邻接表存储结构定义如下:这种带入度的邻接表存储结构定义如下:typedef struct edgenode{ /*typedef struct edgenode{ /* 边结点类型定义边结点类型定义 */*/

int adjvex;int adjvex;

struct node *next;struct node *next;

}edgenode;}edgenode;

typedef struct vertexnode /*typedef struct vertexnode /* 带顶点入度的头结点定义带顶点入度的头结点定义 */*/

{ edgenode* firstedge;{ edgenode* firstedge;

vertextype vertex;vertextype vertex;

int indegree; int indegree; /*/* 顶点的入度域顶点的入度域 */*/

}vertexnode;}vertexnode;typedef struct{ /*AOVtypedef struct{ /*AOV 网络的邻接表结构网络的邻接表结构 */*/ vertexnode adjlist[MAX_VERTEX];vertexnode adjlist[MAX_VERTEX]; int vexnum,arcnum;int vexnum,arcnum;}aovgraph;}aovgraph;

Page 114: 数据结构 第 7 章  图

数据结构 114

Status TopologicalSort(ALGraph G){ FindInDegree(G, indegree); // 对各顶点求入度

InitStack(S); for (i=0; i<G.vexnum; ++i) // 建零入度顶点栈 S

if (!indegree[i]) Push(S, i); // 入度为 0者进栈 count = 0; // 对输出顶点计数

while (!StackEmpty(S)) { Pop(S, i); printf(i, G.vertices[i].data); ++count;

for(p=G.vertices[i].firstarc; p;p=p->nextarc){ k = p->adjvex;

if(!(--indegree[k])) Push(S, k); } } if (count<G.vexnum) return ERROR;// 该有向图有回路 else return OK;} // TopologicalSort

Page 115: 数据结构 第 7 章  图

数据结构 115

关键路径 如果在无有向环的带权有向图中如果在无有向环的带权有向图中

– 用有向边表示一个工程中的活动用有向边表示一个工程中的活动 (Activity)(Activity)– 用边上权值表示活动持续时间用边上权值表示活动持续时间 (Duration)(Duration)– 用顶点表示事件 用顶点表示事件 (Event)(Event)

则这样的有向图叫做用边表示活动的网络,简称 则这样的有向图叫做用边表示活动的网络,简称 AOE (Activity On Edges) AOE (Activity On Edges) 网络。网络。

AOEAOE网络在某些工程估算方面非常有用。例如,网络在某些工程估算方面非常有用。例如,可以使人们了解:可以使人们了解:

(1) (1) 完成整个工程至少需要多少时间完成整个工程至少需要多少时间 ? ? (2) (2) 为缩短完成工程所需的时间为缩短完成工程所需的时间 , , 应当加快应当加快哪些活动哪些活动 ??

Page 116: 数据结构 第 7 章  图

数据结构 116

V3

V1

a4=3

a1=3

a2=2 a6=3a5=4

a3=2 a7=2a8=1

顶点表示事件

边表示活动

事件 Vj发生表示 akj 已结束

ak VjVi

事件 Vi发生表示 ak可以开始

AOEAOE网网

V2

V4

V5

V6

Page 117: 数据结构 第 7 章  图

数据结构 117

由于整个工程只有一个开始点和一个完成点,故由于整个工程只有一个开始点和一个完成点,故AOEAOE网中只有一个入度为网中只有一个入度为 00的点(源点)和一个的点(源点)和一个出度为出度为 00的点(汇点)。的点(汇点)。

由于由于 AOVAOV网中有些活动可以并行地进行,所以完网中有些活动可以并行地进行,所以完成整个工程的最短时间是从开始点到完成点的最成整个工程的最短时间是从开始点到完成点的最长路径的。长路径的。这条路径长度最长的路径叫做关键路这条路径长度最长的路径叫做关键路径径 (Critical Path)(Critical Path) 。。

要找出关键路径,必须找出关键活动,即不按期完成就会影响整个工程完成的活动。关键活动特征:关键活动特征: ee (( ii )) =l=l (( ii ),其中),其中 ee(( ii )表示活动)表示活动 aiai 的最早开始时间。的最早开始时间。 ll (( ii )表)表示在不影响其它活动开始情况下的最迟开始时间。 示在不影响其它活动开始情况下的最迟开始时间。 ll (( ii )) -e-e (( ii )的值表示完成活动)的值表示完成活动 aiai 的时间余的时间余量量

Page 118: 数据结构 第 7 章  图

数据结构 118

vvee (( 00)) =0=0;;

vvee (( ii )) = = )(

)11}(,)(max{

ipj

nivvjve ij

持续的时间活动

vi

集合集合 p(i)p(i)

最早开始时间的确定

Page 119: 数据结构 第 7 章  图

数据结构 119

求每一个顶点求每一个顶点 ii 的最晚允许发生时间的最晚允许发生时间 vvll (( ii )可以)可以沿图中的汇点开始,按图中的逆拓扑序逐个递推出沿图中的汇点开始,按图中的逆拓扑序逐个递推出每个顶点的每个顶点的 vvll (( ii )。)。 vvll (( n-1n-1 )) =v=vee (( n-1n-1 ); );

vvll (( ii )) = = )(

)20)}(,()(min{

isj

nivvlenjv jil

vi

集合集合 s(i)s(i)

最迟开始时间的确定

Page 120: 数据结构 第 7 章  图

数据结构 120

关键路径的实现Status TopologicalOrder(ALGraph G, Stack &T){ InitStack(S); FindInDegree(G, indegree); // 对各顶点求入度 for (int j=0; j<G.vexnum; ++j ) if (indegree[j]==0) Push(S, j); InitStack(T);//建拓扑序列顶点栈 T count = 0; for(int i=0; i<G.vexnum; i++) ve[i] = 0;

Page 121: 数据结构 第 7 章  图

数据结构 121

while(!StackEmpty(S)) { Pop(S, j); Push(T, j); ++count; for (p=G.vertices[j].firstarc; p; p=p->nextarc){

k = p->adjvex; if (--indegree[k] == 0) Push(S, k); if (ve[j]+p->info > ve[k]) ve[k] = ve[j]+p->info; }//for }//while if (count<G.vexnum) return ERROR; else return OK; } // TopologicalOrder

Page 122: 数据结构 第 7 章  图

数据结构 122

Status CriticalPath(ALGraph G) { if (!TopologicalOrder(G, T)) return ERROR; for(a=0; a<G.vexnum; a++) vl[a] = ve[G.vexnum-1]; while (!StackEmpty(T)) for (Pop(T, j), p=G.vertices[j].firstarc; p; p=p->nextarc) {

k=p->adjvex; dut=p->info; if (vl[k]-dut < vl[j]) vl[j] = vl[k]-dut; }

Page 123: 数据结构 第 7 章  图

数据结构 123

for (j=0; j<G.vexnum; ++j)// 求 ee,el 和关键活动

for (p=G.vertices[j].firstarc; p; p=p->nextarc){

k=p->adjvex;dut=p->info; ee = ve[j]; el = vl[k]-dut; tag = (ee==el) ? '*' : ' '; printf(j, k, dut, ee, el, tag); } return OK;} // CriticalPath

Page 124: 数据结构 第 7 章  图

数据结构 124

1. 1. 对于下面的无向图,试给出对于下面的无向图,试给出

(( 11 )图中每个顶点的度;)图中每个顶点的度;

(( 22 )该图的邻接矩阵;)该图的邻接矩阵;

(( 44 )该图的连通分量。)该图的连通分量。

v0

v3 v4

v2

v1 v5 v6

无向图无向图

Page 125: 数据结构 第 7 章  图

数据结构 125

2. 2. 给定下面的有向图,试给出给定下面的有向图,试给出

(( 11 )顶点)顶点 DD的入度与出度;的入度与出度;

(( 22 )该图的出边表与入边表;)该图的出边表与入边表;

(( 33 )该图的强连通分量。 )该图的强连通分量。

A

B

C

D

E

有向图有向图