第七章 图

77
第 1 第

Upload: carrieann-thompson

Post on 30-Dec-2015

35 views

Category:

Documents


4 download

DESCRIPTION

第七章 图. 第七章 图 7.1 图的定义和术语 7.2 图的存储结构 7. 3 图的遍历 7.4 图的连通性问题 7.5 有向无环图及应用 7.6 最短路径. 第七 章 图. 本章介绍另一种非线性数据结构 —— 图 图:是一种多对多的结构关系,每个元素可以有零个或多个直接前趋;零个或多个直接后继;. 第七 章 图. 学习要点 1.熟悉图的各种存储结构及其构造算法,了解实际问题的求解效率与采用何种存储结构和算法有密切联系; - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第七章 图

第 1 页

Page 2: 第七章 图

第 2 页

第七章 图7.1 图的定义和术语7.2 图的存储结构7.3 图的遍历7.4 图的连通性问题7.5 有向无环图及应用7.6 最短路径

Page 3: 第七章 图

第 3 页

第七 章 图

本章介绍另一种非线性数据结构 —— 图 图:是一种多对多的结构关系,每个元素可以有零个或多个直接前趋;零个或多个直接后继;

Page 4: 第七章 图

第 4 页

第七 章 图 学习要点1 .熟悉图的各种存储结构及其构造算法,了解实际问题的求解效率与采用何种存储结构和算法有密切联系;2 .熟练掌握图的两种遍历:深度优先遍历和广度优先遍历的算法。在学习中应注意图的遍历算法与树的遍历算法之间的类似和差异。树的先根遍历是一种深度优先搜索策略,树的层次遍历是一种广度优先搜索策略3 .理解课件中讨论的各种图的算法;

Page 5: 第七章 图

第 5 页

7.1 图的定义和术语一 图的概念 图 G 由两个集合构成,记作 G=<V,E> 其中 V 是顶点的非空有限集合, E 是边的有限集合,其中边是顶点的无序对或有序对集合。

例 G1=<V1,E1>V1={v1,v2,v3,v4 ,v5 }

E1={(v1,v2),(v1,v3),(v2,v3),(v2,v5),(v3,v4),(v3,v5)}

G1 图示

无序对 (vi,vj) :用表示顶点 vi、 vj 的线段

,称为无向边; V5

V1

V2

V4

V3

Page 6: 第七章 图

第 6 页

7.1 图的定义和术语例 G2=<V2,E2>V2={v1,v2,v3,v4 }

E2={<v1,v2>, <v1,v3>, <v3,v4> , <v4,v1>}

G2 图示有序对 <vi,vj> :用以表示以 vi 起点、以 vj

为终点的有向线段,称为有向边或弧;

无向图:在图 G 中,若所有边是无向边,则称 G 为无向图;有向图:在图 G 中,若所有边是有向边,则称 G 为有向图;混和图:在图 G 中,即有无向边也有有向边,则称 G 为混合图;

V1 V2

V3 V4

V1称为弧尾 ( 初始

点 )

V3称为弧头 ( 终端

点 )

Page 7: 第七章 图

第 7 页

7.1 图的定义和术语贰 图的应用举例

例 1 交通图(公路、铁路) 顶点:地点 边:连接地点的公路 交通图中的有单行道双行道,分别用有向边、无向边表示;例 2 电路图 顶点:元件 边:连接元件之间的线路例 3 通讯线路图 顶点:地点 边:地点间的连线例 4 各种流程图 如产品的生产流程图 顶点:工序 边:各道工序之间的顺序关系

V5

V1

V2

V4

V3

Page 8: 第七章 图

第 8 页

7.1 图的定义和术语三 图的基本操作1 CreateGraph(&G, V, VR);初始条件: V 是图的顶点集, VR 是图中弧的集合操作结果:按 V 和 VR 的定义构造图 G2 DestroyGraph(&G);初始条件:图 G 存在操作结果:销毁图 G3 LocateVex(G,u);初始条件:图 G 存在, u 和 G 中顶点有相同特征操作结果:若 G 中存在顶点 u ,则返回该顶点在图中位置;否则返回其它信息。4 GetVex(G, v);初始条件:图 G 存在, v 是 G 中某个顶点操作结果:返回 v 的值5 PutVex(&G, v, value);初始条件:图 G 存在, v 是 G 中某个顶点操作结果:对 v 赋值 value

Page 9: 第七章 图

第 9 页

7.1 图的定义和术语6 FirstAdjVex(G, v);初始条件:图 G 存在, v 是 G 中某个顶点操作结果:返回 v 的第一个邻接顶点。若顶点在 G 中没有邻接顶点,则返回“空”。7 NextAdjVex(G, v, w);初始条件:图 G 存在, v 是 G 中某个顶点, w 是 v 的邻接顶点。操作结果:返回 v 的(相对于 w 的)下一个邻接顶点。若 w 是 v 的最后一个邻接点,则返回“空”。8 InsertVex(&G, v);初始条件:图 G 存在, v 和图中顶点有相同特征。操作结果:在图 G 中增添新顶点 v9 DeleteVex(&G, v);初始条件:图 G 存在, v 和图中顶点有相同特征操作结果:删除 G 中顶点 v 及相关的弧

Page 10: 第七章 图

第 10 页

7.1 图的定义和术语10 InsertArc(&G, v, w); 初始条件:图 G 存在, v 和w 是 G 中两个顶点。操作结果:在 G 中增添弧 <v,w> ,若 G 是无向的,则还增添对称弧<w,v>11 DeleteArc(&G, v, w);初始条件:图 G 存在, v 和w 是 G 中两个顶点。操作结果:在 G 中删除弧 <v,w> ,若 G 是无向的,则还删除对称弧<w,v>12 DFSTraverse(G, v, Visit( ));初始条件:图 G 存在, v 是 G 中某个顶点, Visit 是顶点的应用函数。操作结果:从顶点 v 起深度优先遍历图 G ,对每个顶点调用函数 Visit一次且仅一次。一旦 visit( ) 失败,则操作失败13 BFSTraverse(G, v, Visit( ));初始条件:图 G 存在, v 是 G 中某个顶点, Visit 是顶点的应用函数。操作结果:从顶点 v 起广度优先遍历图 G ,对每个顶点调用函数 Visit一次且一次。一旦 visit( ) 失败,则操作失败

Page 11: 第七章 图

第 11 页

7.1 图的定义和术语叁 图的基本术语

1 邻接点及关联边 邻接点:边的两个顶点 关联边:若边 e= (v, u), 则称顶点 v、 u 关联边 e (边 e 依附于顶点 v,u)2 顶点的度、入度、出度

顶点 V 的度 =与 V 相关联的边的数目 在有向图中: 顶点 V 的出度 =以 V 为起点有向边数 顶点 V 的入度 =以 V 为终点有向边数 顶点 V 的度 = V 的出度 +V 的入度 设图 G 的顶点数为 n ,边数为 e 图的所有顶点的度数和 = 2*e (每条边对图的所有顶点的度数和“贡献” 2 度)

e1

V1 V2

V3 V4

V5

V1

V2

V4

V3

Page 12: 第七章 图

第 12 页

3 有向完全图、无向完全图有向完全图—— n 个顶点的有向图最大边数是 n(n-1)

无向完全图—— n 个顶点的无向图最大边数是 n(n-1)/2

权 (weight)—— 与图的边或弧相关的数叫 ~

网——带权的图叫 ~

7.1 图的定义和术语

Page 13: 第七章 图

第 13 页

7.1 图的定义和术语

4 路径、回路 无向图中的顶点序列 v1,v2,… ,vk, 若 (vi,vi+1)E( i=1,2,…k-

1), v =v1, u =vk, 则称该序列是从顶点 v 到顶点 u 的路径;若v=u ,则称该序列为回路;

有向图 D=(V, E )中的顶点序列 v1,v2,… ,vk, 若 <vi,vi+1>E ( i=1,2,…k-1), v =v1, u =vk, 则称该序列是从顶点 v 到顶点 u 的路径;若 v=u ,则称该序列为回路;

例 在图 1 中, V1,V2,V3,V4 是 V1到 V4 的路径;

V1,V2,V3,V4,V1 是回路;在图 2 中, V1,V3,V4 是 V1到 V4的路径; V1,V3,V4,V1 是回路;

V5

V1

V2

V4

V3

V1 V2

V3 V4

图 1 图 2

Page 14: 第七章 图

第 14 页

7.1 图的定义和术语5 连通图、(强连通图) 在无(有)向图 G=< V, E > 中,若对任何两个顶点 v、 u 都存在从 v

到 u 的路径,则称 G 是连通图(强连通图)

V5

V6

V3

V1

V2

V4

连通图 非连通图

V5

V1

V2

V4

V3

Page 15: 第七章 图

第 15 页

7.1 图的定义和术语6 子图 设有两个图 G=( V, E)、 G1=( V1, E1),若 V1 V, E1

E, E1 关联的顶点都在 V1 中,则称 G1是 G 的子图;例 图 2 、图 3 是 图 1 的子图

V5

V1

V2

V4

V3

V5

V1

V2

V3

V5

V1

V2

V4

V3

图 1 图 2 图 3

Page 16: 第七章 图

第 16 页

7.1 图的定义和术语7 连通分图(强连通分量) 无向图 G 的极大连通子图称为 G 的连通分量 极大连通子图意思是:该子图是 G 连通子图,将 G 的任何不在该子

图中的顶点加入,子图不再连通; 有向图 D 的极大强连通子图称为 D 的强连通分量 极大强连通子图意思是:该子图是 D强连通子图,将 D 的任何不在

该子图中的顶点加入,子图不再是强连通的;

V5

V6

V3

V1

V2

V4

连通分图

Page 17: 第七章 图

第 17 页

7.1 图的定义和术语

V5

V1 V2

V4

V3

V5

V1 V2

V4

V3

8 生成树( 包含无向图 G 所有顶点的的极小连通子图称为 G 生成树 极小连通子图意思是:该子图是 G 的连通子图,在该子图中删除任何一条边,子图不再连通, 若 T是 G 的生成树当且仅当 T满足如下条件 T是 G 的连通子图 T包含 G 的所有顶点 T 中无回路 只有足以构成一棵树的 n-1 条边

Page 18: 第七章 图

第 18 页

例 2

1 3

2

1 3

有向完全图 无向完全图

3

5

6

2 4 5

1 3 6

图与子图例

2 4 5

1 3 6G1

顶点 2 入度: 1 出度: 3顶点 4 入度: 1 出度: 0

例1 5 7

3 2 4G2

6

顶点 5 的度: 3顶点 2 的度: 4

Page 19: 第七章 图

第 19 页

1 5 7

3 2 4

G2

6

2 4 5

1 3 6

G1

路径: 1, 2, 3, 5, 6, 3路径长度: 5简单路径: 1, 2, 3, 5回路: 1, 2, 3, 5, 6, 3,1简单回路: 3, 5, 6, 3

路径: 1, 2, 5, 7, 6, 5, 2, 3路径长度: 7简单路径: 1, 2, 5, 7, 6回路: 1, 2, 5, 7, 6, 5, 2, 1简单回路: 1, 2, 3, 1

Page 20: 第七章 图

第 20 页

连通图

例2 4 5

1 3 6

强连通图3

5

6

非连通图连通分量

例2 4 5

1 3 6

Page 21: 第七章 图

第 21 页

第七 章 图

7.2 图的存储结构

壹 数组表示法

贰 邻接表

Page 22: 第七章 图

第 22 页

7.2 图的存储结构 图是多对多的结构,比线性结构、树结构复杂,所以其存储结构也要复杂些。与线性结构、树结构一样,图的存储结构至少要保存两类信息: 1) 顶点的数据 2) 顶点间的关系顶点的编号 为了使图的存储结构与图一一对应,在讨论图的存储结构时,首先要给图的所有顶点编号。

本课程介绍两类图的存储结构数组表示法邻接表(邻接表,逆邻接表)

设 G=<V, E> 是图 , V={v1,v2,v3, … vn }, 设顶点的的角标为它的编号

如何表示顶点间的关系?

Page 23: 第七章 图

第 23 页

7.2 图的存储结构

邻接矩阵: G 的邻接矩阵是满足如下条件的 n 阶矩阵:

一 数组表示法

数组表示法是图的一种顺序存储结构在数组表示法中,用邻接矩阵表示顶点间的关系

A[i][j]=1 若 (vi,vi+1)E 或 <vi,vi+1>E

0 否则

V5

V1

V2

V4

V3

0 1 0 1 01 0 1 0 10 1 0 1 11 0 1 0 00 1 1 0 0

0 1 1 00 0 0 00 0 0 11 0 0 0

V1 V2

V3 V4

Page 24: 第七章 图

第 24 页

7.2 图的存储结构数组表示法顶点的存储:用一维数组存储(按编号顺序)顶点间关系:用二维数组存储图的邻接矩阵;

012345

m-1

V1V2V3V4V5

存储顶点的一维数组

存储邻接矩阵的二维数组

01010

10101

01234

mm+1m+2m+3m+4

Page 25: 第七章 图

第 25 页

7.2 图的存储结构数组表示法类型定义#define INFINITY INT_MAX#define MAX_VERTEX_NUM 20typedef enum{DG, DN, AG, AN} GraphKind;typedef struct ArcCell{ VRType adj; InfoType *info;}ArcCell, AdjMatrix[MAX_VERTEX_NUM ][MAX_VERTEX_NUM ]typedef struct { VetexType vexs[MAX_VERTEX_NUM ]; AdjMatrix arc; int vexnum, arcnum; GraphKind kind;}MGraph;

Page 26: 第七章 图

第 26 页

7.2 图的存储结构

设 G 是Mgraph 类型的变量,用于存储无向图,该图有 n 个顶点, e条边

G 的图示如下:G.vexs

G.arcs

G.vexnumG.arcnu G.kind

V1

0

ne

AG

顶点数组

存储邻接矩阵的二维数组

Page 27: 第七章 图

第 27 页

7.2 图的存储结构

无向图数组表示法特点:1 )无向图邻接矩阵是对称矩阵,同一条边表示了两次;2 )顶点 v 的度:等于二维数组对应行(或列)中 1 的个数;3 )判断两顶点 v、 u 是否为邻接点:只需判二维数组对应分量是否为 1;4 )顶点不变,在图中增加、删除边:只需对二维数组对应分量赋值 1或清 0 ;5 )设存储顶点的一维数组大小为 m(m 图的顶点数 n), G 占用存储空间: m+m2; G 占用存储空间只与它的顶点数有关,与边数无关;适用于边稠密的图;对有向图的数组表示法可做类似的讨论

Page 28: 第七章 图

第 28 页

7.2 图的存储结构贰 邻接表 邻接表是图的链式存储结构1 无向图的邻接表顶点:通常按编号顺序将顶点数据存储在一维数组中;关联同一顶点的边:用线性链表存储

V5

V1

V2

V4

V3

例 0 1 2 3 4

m-1

V1V2V3V4V5

1 3

422

1

10

0 43

该结点表示边( V1 V2) ,

其中的 1是 V2在一维数组中的

位置

Page 29: 第七章 图

第 29 页

7.2 图的存储结构图的邻接表类型定义#define MAX_VERTEX_NUM 20typedef struct ArcNode{ // 边(弧)结点的类型定义int adjvex; // 边(弧)的另一顶点的在数组中的位置struct ArcNode *nextarc; //指向下一条边(弧)结点的指针InfoType *info;}ArcNode;typedef struct VNode { // 顶点结点和数组的类型定义VertexType data; // 顶点信息ArcNode * finrstarc; //指向关联该顶点的边(弧)链表}VNode, AjList[MAX_VERTEX_NUM];typedef struct {AdjList vertices;int vexnum, arcnum; // 图的当前顶点数和弧数int kind; // 图的种类标志}ALGraph;

Page 30: 第七章 图

第 30 页

7.2 图的存储结构设 G 是 ALGraph 类型的变量,用于存储无向图 G1 ,该图有 n 个顶点, e 条边

G 的图示如下:

V5

V1

V2

V4

V3

无向图 G1

该结点表示边( V5,V2) ,

其中的 1是 V2在一维数组中的

位置

G.vertices

G.vexnum

G.arcnu

G.kind

0 1 2 4

m-1

V1V2V3V4V5

ne

AG

1 3

422

1

10

0 43

data firstarc adjvex nextarc

Page 31: 第七章 图

第 31 页

7.2 图的存储结构

无向图的邻接表的特点 1 )在 G 邻接表中,同一条边对应两个结点; 2 )顶点 v 的度:等于 v 对应线性链表的长度; 3 )判定两顶点 v , u 是否邻接:要看 v 对应线性链表中有无对应的结点 4 )在 G 中增减边:要在两个单链表插入、删除结点;

Page 32: 第七章 图

第 32 页

7.2 图的存储结构

D.vertices

D.vexnum D.arcnu

D.kind

V1

V2

V3

V4

ne

DG

1 2

30

V1 V2

V3 V4

2 有向图的邻接表和逆邻接表1 )有向图的邻接表顶点:用一维数组存储(按编号顺序)以同一顶点为起点的弧:用线性链表存储

类似于无向图的邻接表,所不同的是:

以同一顶点为起点的弧:用线性链表存储

Page 33: 第七章 图

第 33 页

7.2 图的存储结构2 )有向图的逆邻接表顶点:用一维数组存储(按编号顺序)以同一顶点为终点的弧:用线性链表存储表

类似于无向图的邻接表,所不同的是:

以同一顶点为终点的弧:用线性链表存储

D.vertices

D.vexnum D.arcnu

D.kind

V1V2V3V4

ne

DG

002

3

V1 V2

V3 V4

Page 34: 第七章 图

第 34 页

7.2 图的存储结构

在不同的存储结构下,实现各种操作的效率可能是不同的。所以在求解实际问题时,要根据求解问题所需操作,选择合适的存储结构。

Page 35: 第七章 图

第 35 页

第七 章 图

7.3 图的遍历

一 深度优先遍历

二 广度优先遍历

Page 36: 第七章 图

第 36 页

7.3 图的遍历

图的遍历:从图的某顶点出发,访问图中所有顶点,并且每个顶点仅访问一次。 图中可能有回路,遍历可能沿回路又回到已遍历过的结点。为避免同一顶点被多次访问,必须为每个被访问的顶点作一标志。为此引入一辅助数组, 记录每个顶点是否被访问过。 有两种遍历方法(它们对无向图,有向图都适用): 深度优先遍历 广度优先遍历

Page 37: 第七章 图

第 37 页

7.3 图的遍历一 深度优先遍历从图中某顶点 v 出发: 1 )访问顶点 v;2 )从 v 的未被访问的邻接点出发,继续对图进行深度优先遍历;

例 图 G 中,以 V1 起点的的深度优先序列: ( 1 ) V1,V2,V4,V5,V8,V3,V6,V7, ( 2 ) V1,V2,V5,V8,V4,V3,V6,V7

V8

V7

V6

V5

V4

V3

V2

V1由于没为有规定

访问邻接点的顺序,深度优先序列不是唯一的

这是序列( 1)在遍历过程中所经过的路

注:为简单起见,只讨论非空连通图的遍历

Page 38: 第七章 图

第 38 页

7.3 图的遍历深度优先遍历 (设图为非空连通图)从图中某顶点 v 出发: 1 )访问顶点 v;2 )从 v 的未被访问的邻接点出发,继续对图进行深度优先遍历;

先序遍历( DLR) 若二叉树非空 ( 1 )访问根结点; ( 2 )先序遍历左子树; ( 3 )先序遍历右子树;

如果将图顶点的邻接点看作二叉树结点的左、右孩子

深度优先遍历与先序遍历是不是很类似?

V8

V7

V6

V5

V4

V3

V2

V1

Page 39: 第七章 图

第 39 页

7.3 图的遍历

深度优先遍历算法void DFS(Graph G, int v, Status(*Visit(int v)) {

// 从第 v 个顶点出发,递归地深度优先遍历图 G 。 // v 是顶点在一维数组中的位置,假设 G 是非空图visited[v] =TRUE; Visit(v); //访问第 v 个顶点for (w= FirstAdjVex(G, v); w; w=NextAdjVex(G, v, w))

if (!visited[w]) DFS(G, w); //对 v 的尚未访问的邻接顶点 w递归调用DFS

Boolean visited[MAX_VERTEX_NUM] //访问标志数组 , 全局变量,初始值:所有分量全为False(0)//visited[v]=TRUE 表示顶点 v 已被访问

visited 01234

m-1

00000

Page 40: 第七章 图

第 40 页

7.3 图的遍历

先序遍历递归算法 void PreOrderTraverse(BiTree T, Status(*Visit)(TElemType e)) {// 本算法先序遍历以 T 为根结点指针的二叉树。 if (T) { // 若二叉树为空,结束返回 Visit(T->data); PreOrderTraverse(T->lchild, Visit); PreOrderTraverse(T->rchild, Visit); }//PreOrderTraverse

如果将图顶点的邻接点看作二叉树结点的左、右孩子

深度优先遍历算法与先序遍历算法

的结构是不是很像?

深度优先遍历算法void DFS(Graph G, int v, Status(*Visit(int v)) {// 从第 v 个顶点出发,递归地深度优先遍历图 G 。 // v 是顶点在一维数组中的位置,假设 G 是非空图visited[v] =TRUE; Visit(v); //访问第 v 个顶点for (w= FirstAdjVex(G, v); w; w=NextAdjVex(G, v, w))if (!visited[w]) DFS(G, w); //对 v 的尚未访问的邻接顶点 w递归调用DFS

Page 41: 第七章 图

第 41 页

7.3 图的遍历贰 广度优先遍历(类似于树的按层遍历) 从图中某顶点 v 出发:1 )访问顶点 v ;

2 )访问 v 的所有未被访问的邻接点 w1 ,w2 , …wk ;

3 )依次从这些邻接点出发,访问它们的所有未被访问的邻接点 ; 依此类推,直到图中所有访问过的顶点的邻接点都被访问;

例 图 G 中,以 V1 起点的的广度优先序列: ( 1) V1,V2,V3,V4,V5,V6,V7,V8 ( 2) V1,V3,V2,V6,V7,V4,V5,V8

V8

V7

V6

V5

V4

V3

V2

V1

这是序列( 1)在遍历过程中所经过的路

由于没为有规定访问邻接点的顺序,

广度优先序列不是唯一的

Page 42: 第七章 图

第 42 页

7.3 图的遍历广义优先遍历算法从图中某顶点 v 出发:1 )访问顶点 v ;(容易实现)2 )访问 v 的所有未被访问的邻接点 w1 ,w2 , …wk ; (容易实现)3 )依次从这些邻接点(在步骤 2 )访问的顶点)出发,访问它们的所有未被访问的邻接点 ; 依此类推,直到图中所有访问过的顶点的邻接点都被访问;为实现 3 ),需要保存在步骤 (2 )中访问的顶点,而且访问这些顶点邻接点的顺序为:先保存的顶点,其邻接点先被访问。

在广度优先遍历算法中,需设置一队列 Q,

保存已访问的顶点,并控制遍历顶点的顺序。

Page 43: 第七章 图

第 43 页

7.3 图的遍历void BFSTraverse(Graph G,int v,Status (* Visit)(int v)) {//从 v 出发,广度优先遍历连通图 G 。 v 是顶点在一维数组中的位置,使用辅助队列 Q 和访问标志数组 visited 。 for (u=0; u< G.vexnum; ++u) visited[u]=FALSE; InitQueue(Q); //建空的辅助队列 Q Visited[v]=TRUE; Visit(v), EnQueue(Q,v) //访问 v,v 入队 While(!QueueEmpty(Q)){ DeQueue(Q,u); //队头元素出队 ,并赋值给 u //访问 u 所有未被访问的邻接点 for(w=FirstAdjVex(G,u); w; w=NextAdjVex(G,u,w)) if(!visited[w]){ // 若w 尚未访问 Visited[w]=TRUE; Visit(w);EnQueue(Q,w); }//if }//while}//BFSTraverse

Page 44: 第七章 图

第 44 页

7.3 图的遍历

非连通图的遍历上面介绍了连通图的深度优先遍历算法,对非连通图 , 可从每个连通分量选一起点,调用遍历算法(如 DFS )完成各连通分量的深度先遍历。例 图 G 的深度优先序列: V1,V2,V3,V4,V5,V6,

广度优先序列 V1,V2,V3,V4,V5,V6,

V3

V1

V2

V4

V5

V6

V3

V1

V2

V4

V5

V6

深度优先遍历所经过的路径 广度优先遍历所经过的路径

Page 45: 第七章 图

第 45 页

7.4.1 图的连通性问题 -- 无向图的连通分量和生成树

– 生成树定义:所有顶点均由边连接在一起,但不存在回

路的图叫 ~深度优先生成树与广度优先生成树生成森林:非连通图每个连通分量的生成树一起组成非连通图的 ~

7.4 图的连通性

Page 46: 第七章 图

第 46 页

7.4.1 图的连通性问题 -- 无向图的连通分量和生成树说明

–一个图可以有许多棵不同的生成树–所有生成树具有以下共同特点:

生成树的顶点个数与图的顶点个数相同生成树是图的极小连通子图一个有 n 个顶点的连通图的生成树有 n-1 条边生成树中任意两个顶点间的路径是唯一的在生成树中再加一条边必然形成回路

–含 n 个顶点 n-1 条边的图不一定是生成树

G

H

K I

Page 47: 第七章 图

第 47 页

V1

V2

V4 V5

V3

V7V6

V8

例深度遍历: V1 V2 V4 V8 V5 V3 V6 V7

V1

V2

V4

V5

V3

V7

V6

V8

深度优先生成树

V1

V2

V4 V5

V3

V7V6

V8

广度优先生成树

V1

V2

V4 V5

V3

V7V6

V8V1

V2

V4 V5

V3

V7V6

V8

广度遍历: V1 V2 V3 V4 V5 V6 V7 V8

Page 48: 第七章 图

第 48 页

例A B

L M

C

F

D E

G H

KI

J

A

B

L

M

C F

J

D

E

G

H

K I

深度优先生成森林

Page 49: 第七章 图

第 49 页

void DFSTree(Graph G,int v ,CSTree *T){/* 从第 v 个顶点出发深度优先遍历图 G ,建立以 *T 为根的生成树 */ visited[v]=TRUE; first=TRUE; for(w=FirstAdjVex(G,v); w; w=NextAdjVex(G,v,w)) if(!visited[w]) { p=(CSTree)malloc(sizeof)CSNode)); /* 分配孩子结点 */ *p={GetVex(G,w),NULL,NULL}; if (first) /*w是 v 的第一个未被访问的邻接顶点,作为根的左孩子结点

*/ { T->lchild=p; first=FALSE; } else { /*w是 v 的其它未被访问的邻接顶点,作为上一邻接顶点的右兄弟 */ q->nextsibling=p; } q=p; DFSTree(G,w,&q); /* 从第 w 个顶点出发深度优先遍历图 G ,建立生成子

树 *q*/ } }

Page 50: 第七章 图

7.4 图的连通性7.4.3 最小生成树

•n 个城市之间 , 最多可能设置 n(n-1)/2 条线路 ,而连通 n 个城市只需要 n-1 条线路 .• 最小 (代价 ) 生成树的定义 .• 一棵生成树的代价 .

Page 51: 第七章 图

7.4 图的连通性

最小生成树 MST 的性质 : 假设 N=(V,{E}) 是一个连通网 ,U 是顶点集 V 的一个非空子集 .若 (u,v) 是一条具有最小权值 (代价 ) 的边 , 其中 u属于 U,v属于 V-U, 则必存在一棵包含边 (u,v) 的最小生成树 .

Page 52: 第七章 图

7.4 图的连通性算法一:(普里姆算法)

假设 N=(V,{E}) 是连通网 ,TE是 N上最小生成树中边的集合 . 算法从 U={u0}(u0属于V),TE={}开始 ,重复执行下述操作 : 在所有 u属于 U,v属于 V-U 的边 (u,v)属于E 中找一条代价最小的边 (u0,v0)并入集合 TE, 同时 v0并入 U, 直至 U=V 为止 . 此时 TE 中必有 n-1 条边 ,则 T=(V,{TE})为 N 的最小生成树 .

Page 53: 第七章 图

为实现这个算法需要附设一个辅助数组closedge, 以记录从 U到 V-U具有最小代价的边 . 对每个顶点 vi属于 V-U, 在辅助数组中存在一个相应分量 closedge[i-1], 它包括两个域 , 其中 lowcost 存储该边上的权 .显然 :

closedge[i-1].lowcost=Min{cost(u,vi)|u属于 U} vex域存储该边依附的在 U 中的顶点 .

7.4 图的连通性

Page 54: 第七章 图

普里姆算法构造最小生成树的过程

v2 v4

v6

v3

v1

v5

v1

v4

v6v5

v2

v3

6 515

3 46 26

(a)

1

4 2

5

35

7.4 图的连通性

Page 55: 第七章 图

普里姆算法void MiniSpanTree_PRIM(MGraph G, VertexType u) { // 用普里姆算法从第 u 个顶点出发构造网 G 的最小生成树 T , //输出 T 的各条边。 // 记录从顶点集 U到 V-U 的代价最小的边的辅助数组定义:struct { VertexType adjvex ; VRType lowcost ; } closedge[MAX_VERTEX_NUM];

7.4 图的连通性

Page 56: 第七章 图

k=LocateVex( G, u );for( j=0; j<G.vexnum; ++j ) //辅助数组初始化 if( j! =k) closedge[j]={u, G.arcs[k][j].adj} ; //{adjvex, lowcost}

closedge[k].lowcost=0 ; // 初始, U={u}for( i=1; i<G.vexnum; ++i ) {//选择其余 G.vexnum-1 个顶点 k=minimum( closedge ); // 求出 T 的下一个结点:第 k 顶点 //此时 closedge[k].lowcost= //MIN{ closedge[vi].lowcost | closedge[vi].lowcost>0, vi V-U}∈

printf( closedge[k].adjvex, G.vexs[k] ); //输出生成树的边 closedge[k].lowcost=0 ; //第 k 顶点并入 U 集 for( j=0; j<G.vexnum; ++j ) if( G.arcs[k][j].adj<closedge[j].lowcost ) // 新顶点并入 U 后重新选择最小边 closedge[j]={G.vexs[k], G.arcs[k][j].adj}; }} //MiniSpanTree

7.4 图的连通性

Page 57: 第七章 图

算法二:(克鲁斯卡尔算法)

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

7.4 图的连通性

Page 58: 第七章 图

克鲁斯卡尔算法构造最小生成树的过程

v2 v4

v6

v3

v1

v5

v1

v4

v6v5

v2

v3

6 515

3 46 26

(a)

1

4 2

5

35

7.4 图的连通性

Page 59: 第七章 图

一般来讲,

由于普里姆算法的时间复杂度为O(n2) ,则适于稠密图;而克鲁斯卡尔算法需对 e 条边按权值进行排序,其时间复杂度为O(eloge) ,则适于稀疏图。

7.4 图的连通性

Page 60: 第七章 图

7.4 图的连通性

“ 最小生成树”主要是针对“无向图”而言的,请思考它主要能解决哪些实际生活中遇到的问题?

Page 61: 第七章 图

第 61 页

7.6 最短路径7.6.1 从某个源点到其余各顶点的最短路径

问题提出用带权的有向图表示一个交通运输网,图中:顶点——表示城市边——表示城市间的交通联系权——表示此线路的长度或沿此线路运输所花的时间或费用等问题:从某顶点出发,沿图的边到达另一顶点所经过的路径中,各边上权值之和最小的一条路径——最短路径

Page 62: 第七章 图

第 62 页

7.6 最短路径7.6.1 从某个源点到其余各顶点的最短路径给定带权有向图 G 和源点 v, 求从 v 到 G 中其余各顶

点的最短路径例 : 求 v0到其余顶点的最短路径

V1

V5

V2

V4

V0

V3

5 50

100

10

60

2010

30 始点 终点 最短路径 路径长度 v0 v1 无 v2 (v0,v2) 10 v3 (v0,v4,v3) 50 v4 (v0,v4) 30 v5 (v0,v4,v3,v5) 60

Page 63: 第七章 图

第 63 页

迪杰斯特拉 (Dijkstra)算法 (1) 设置两个顶点的集合 T和 S;

– 集合 S 存放已找到最短路径的顶点– 集合 T存放当前还未找到最短路径的顶点

(2) 初始状态时 ,S只包含源点 v0 ;

(3)从 T中选取某个顶点 vi( 要求 vi 到 v0 的路径长度最短 ) 加入到S 中 ,;

(4)S 中每加入一个顶点 vi,都要修改顶点 v0到 T中剩余顶点的最短路径长度值 ;

– 它们的值为原来值与新值的较小者 ;

– 新值是 vi 的最短路径长度值加上 vi到该顶点的路径长度

(5)不断重复 (3)和 (4), 直到S 包含全部顶点 ;

Page 64: 第七章 图

第 64 页

V1

V5

V2

V4

V0

V3

5 50

100

10

60

2010

30

迪杰斯特拉 (Dijkstra) 算法举例

带权邻接矩阵为 :

10 30 100 5 50 10 20 60

Page 65: 第七章 图

第 65 页

最短路径的求解过程

终点 v1 v2 v3 v4 v5 vi

步骤 1 10 30 100 v2 (v0,v2) (v0,v4) (v0,v5)步骤 2 60 30 100 v4 (v0,v2,v3) (v0,v4) (v0,v5)步骤 3 50 90 v3 (v0,v4,v3) (v0,v4,v5)步骤 4 60 v5 (v0,v4,v3,v5)步骤 5 无

Page 66: 第七章 图

第 66 页

7.6 最短路径7.6.2 每一对顶点间的最短路径

给定带权有向图 G,求 G 中每个顶点到其余各顶点的最短路径

例 : 求有向网 G 的每一对顶点的最短路径

V0

V2

V1

6

2

4113

有向网 G

0 4 116 0 23 0

邻接矩阵

Page 67: 第七章 图

第 67 页

Floyd 算法

(1)递推产生一个矩阵序列 A0,A1,...,Ak,...An

– 其中 Ak[i,j] 表示从顶点 vi到 vj 的路径上所经过的顶点序号不大于 k的最短路径长度

(2) 初始时 , A0为邻接矩阵 .

(3)Ak+1[i,j]=min{Ak[i,j], Ak[i,k+1]+Ak[k+1,j]}

– (0<=k<=n-1)

0 4 116 0 23 0

A0=

0 4 65 0 23 7 0

A2=0 4 66 0 23 0

A1=

Page 68: 第七章 图

第 68 页

例A

C

B

2

6

4

311

0 4 116 0 23 0

初始: 路径:AB AC

BA BC

CA

0 4 66 0 23 7 0

加入 V2 : 路径:AB ABC

BA BC

CA CAB

0 4 116 0 23 7 0

加入 V1 : 路径:AB AC

BA BC

CA CAB

0 4 65 0 23 7 0

加入 V3 : 路径:AB ABC

BCA BC

CA CAB

Page 69: 第七章 图

第 69 页

7.5 有向无环图及其应用 一个无环的有向图叫做有向无环图简称 DAG 图

有向树 DAG 图有向图

Page 70: 第七章 图

第 70 页

有向无环图是--------描述含有公共子式的表达式的有效工具 .

((a+b)*(b*(c+d))+(c+d)*e)*((c+d)*e)

*

*

* *

*

+

+

+

+

+

a b b

c

c

c

d

d

d

用二叉树描述表达式

e

e

*

* *

*

+

+ +

a b b c d

用 DAG 描述表达式

e

Page 71: 第七章 图

第 71 页

有向无环图也是 ---------描述一项工程或系统的进行过程的有效工具

编号 课程名称 预修课C1 程序设计基础 无C2 离散数学 C1C3 数据结构 C1,C2C4 汇编语言 C1C5 语言设计分析 C3,C4C6 计算机原理 C11C7 编译原理 C5,C3C8 操作系统 C3,C6C9 高等数学 无C10 线性代数 C9C11 普通物理 C9C12 数值分析 C1C9C10

C12

C10

C11

C9

C1

C2

C3

C4

C6

C5

C7

C8

Page 72: 第七章 图

第 72 页

7.5.1 拓扑排序AOV- 网 (Activity On Vertex)

顶点--活动 弧--活动间的优先关系 AOV-网不应该出现有向环

上例的拓扑排序序列之一:C1,C9, C2,C4,C10,C11, C3,C12,C6,C5, C7,C8

Page 73: 第七章 图

第 73 页

7.5.2 关键路径 AOE- 网 (Activity On Edge)

AOE-网是带权的有向无环网 顶点--事件或状态 弧--活动及发生的依次关系 权--活动持续的时间 源点--入度为0的顶点(只有一个) 汇点--出度为0的顶点(只有一个)

V4

V1

V3 V8

V2 V7

V9

V6

V5a1=6

a2=4

a3=5

a4=1

a5=1

a6=2

a7=9

a8=7

a9=4

a10=2

a11=4

Page 74: 第七章 图

第 74 页

AOE- 网要研究的问题

完成整项工程至少需要多少时间?哪些活动是影响整个工程进度的关键? 关键路径:路径长度最长的路径     (从源点到汇点)

e(i) 表示活动 ai 的最早开始时间l(i) 表示活动 ai 的最迟开始时间 (不推迟整个工期 ) e(i)=l(i) 的活动叫做关键活动 , 关键路径上的活动都是关键活动 .ve(j) 表示事件 vj 的最早发生时间vl(j) 表示事件 vj 的最迟发生时间 (不推迟整个工期 )

Page 75: 第七章 图

第 75 页

e(i), l(i), ve(j),vl(j) 的关系

若活动 ai 由弧 <j,k> 表示 , 其持续的时间记为 dut(<j,k>), 则 e(i) = ve(j) l(i) = vl(k) - dut(<j,k>)

Vj Vkai

求 ve(j)和 vl(j) 分两步进行 :(1) 从 ve(0)=0开始向前递推 : ve(j) = max{ve(i) + dut(<i,j>)} i

Vi Vjai

Vi Vjai

(2) vl(n-1)=ve(n-1)开始向后递推 : vl(i) = min{vl(j) - dut(<i,j>)} j

Page 76: 第七章 图

第 76 页

求 AOE 网的关键路径举例

V4

V1

V3 V8

V2 V7

V9

V6

V5a1=6

a2=4

a3=5

a4=1

a5=1

a6=2

a7=9

a8=7

a9=4

a10=2

a11=4

事件j 1 2 3 4 5 6 7 8 9ve(j) 0 6 4 5 7 7 16 14 18vl(j) 0 6 6 8 7 10 16 14 18

活动i 1 2 3 4 5 6 7 8 9 10 11e(i) 0 0 0 6 4 5 7 7 7 16 14l(i) 0 2 3 6 6 8 7 7 10 16 14

Page 77: 第七章 图

第 77 页

V1V8

V2 V7

V9V5a1=6

a4=1 a7=9

a8=7

a10=2

a11=4

整个工期为 18关键路径有两条 :(V1,V2,V5,V7,V9), (V1,V2,V5,V8,V9)关键活动有六个 : a1, a4, a7, a8, a10, a11