1 / 210

第七章 图

第七章 图. 7.1 图的定义和术语 7.2 图的存储结构 7.3 图的遍历 7.4 图的连通性问题 7.5 有向无环图及其应用 7.6 最短路径. 7.1 图的定义和术语. 图( Graph) —— 由一个 顶点集 V 和一个 边集 E 构成的数据结构。 Graph = (V, E ) 其中, V = { x | x  某个数据对象 } 是非空有限的顶点集合; E = {( x , y ) | x , y  V }

kaycee
Télécharger la présentation

第七章 图

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

  2. 7.1 图的定义和术语 • 图(Graph)——由一个顶点集V和一个边集E构成的数据结构。 • Graph = (V, E ) • 其中,V = { x | x 某个数据对象} 是非空有限的顶点集合; E = {(x, y) | x, y V } 或 E = {<x, y> | x, y V && Path (x, y)} 是有限的顶点之间关系的集合,(x,y)也叫做边(edge)集合,它是无方向的; Path (x, y)表示从 x 到 y 的一条单向通路, 它是有方向的,所以<x,y>也叫做弧(arc)的集合,x称为弧尾或始点,y称为弧头或终点.

  3. 7.1 图的定义和术语 • 有向图——有向图G是由两个集合V(G)和E(G)组成的 其中:V(G)是顶点的非空有限集 E(G)是有向边(也称弧)的有限集合,弧是顶点的有序对,记为<v,w>,v,w是顶点,v为弧尾,w为弧头 • 无向图——无向图G是由两个集合V(G)和E(G)组成的 其中:V(G)是顶点的非空有限集 E(G)是边的有限集合,边是顶点的无序对,记为(v,w)或(w,v),并且(v,w)=(w,v)

  4. 2 4 5 1 3 6 G1 例7.2 1 5 7 3 2 4 6 G2 7.1 图的定义和术语 例7.1 图G1中:V(G1)={1,2,3,4,5,6} E(G1)={<1,2>, <2,1>, <2,3>, <2,4>, <3,5>, <5,6>, <6,3>} 图G2中:V(G2)={1,2,3,4,5,6,7} E(G1)={(1,2), (1,3), (2,3), (2,4),(2,5), (5,6), (5,7)}

  5. 7.1 图的定义和术语 • 无向完全图(Completed graph) —n个顶点的无向图有n(n-1)/2条边(最大边数是n(n-1)/2) • 有向完全图——n个顶点的有向图,有n(n-1)条边(最大边数是n(n-1) ) • 稀疏图(sparse graph):边或弧很少的图,通常边数 <nlog2n • 稠密图(Dense graph) • 无向图中,边数接近n(n-1)/2 ; • 有向图中,边数接近n(n-1)

  6. 7.1 图的定义和术语 有向图 有向完全图 无向 完全图 无向图(树) 完全图

  7. 7.1 图的定义和术语 • 权——与图的边或弧相关的数 • 网——带权的有向图叫有向网,带权的无向图叫无向网

  8. 7.1 图的定义和术语 • 子图——如果图G(V,E)和图G’(V’,E’),满足: • V’V,E’E • 则称G‘为G的子图

  9. 7.1 图的定义和术语 • 邻接点(或相邻点),关联 如果 e=(u, v) 是 E(G) 中的一条边,则称 u 与 v 互为邻接顶点或相邻顶点;称边e与顶点u ,v 关联; 如果 e=<u, v>是 E(G) 中的一条弧,则称 u 邻接到v,v邻接于u,也称e与u,v关联;称弧e与顶点u ,v 关联;

  10. 7.1 图的定义和术语 • 顶点的度(于树的度不同) • 无向图中,顶点的度为与每个顶点相连的边数,记作TD(v) • 有向图中,顶点的度分成入度与出度 • 入度:以该顶点为头的弧的数目,记为ID(v) • 出度:以该顶点为尾的弧的数目,记为OD(v) • 一个顶点的度数等于该顶点的入度与出度之和,即TD(v)=OD(v)+ID(v)

  11. 7.1 图的定义和术语 • 路径——路径是顶点的序列V={Vi0,Vi1,……Vin},满足(Vij-1,Vij)E 或 <Vij-1,Vij>E,(1<jn) • 路径长度——沿路径边的数目或沿路径各边权值之和 • 简单路径——序列中顶点不重复出现的路径 • 回路(环)——第一个顶点和最后一个顶点相同的路径 • 简单回路(简单环)——除了第一个顶点和最后一个顶点外,其余顶点不重复出现的回路

  12. 7.1 图的定义和术语 V0V1V3V0 V0V1V3V2 V0V1V3V2V0V1V2

  13. 无向图G的三个连通分量 无向图G A B A B F G E F G E H I J I J H K L K L M M C D C D 7.1 图的定义和术语 • 连通图与连通分量 在无向图中, 若从顶点v1到顶点v2有路径, 则称顶点v1与v2是连通的。如果图中任意一对顶点都是连通的, 则称此图是连通图。非连通图的极大连通子图叫做连通分量。

  14. 7.1 图的定义和术语 • 强连通图与强连通分量 在有向图中,若对于每一对顶点vi和vj, 都存在一条从vi到vj和从vj到vi的路径, 则称此图是强连通图。非强连通图的极大强连通子图叫做强连通分量。 有向图G 有向图G的两个 强连通分量 强连通图

  15. 无向图G 无向图G的生成树 A B A B E E H H M M C D C D 7.1 图的定义和术语 • 生成树:是一个极小连通子图,它含有图中全部n个顶点,但只有n-1条边。 • 如果在生成树上添加1条边,必定构成一个环 • 若图中有n个顶点,却少于n-1条边,必为非连通图。

  16. 有向图G 有向图G的生成森林 7.1 图的定义和术语 • 生成森林: 由若干棵生成树组成,含全部顶点,但构成这些树的边是最少的。

  17. 7.1 图的定义和术语 本章只讨论简单图,有两类图形不在本章讨论之列:

  18. 图的抽象数据类型定义 ADT Graph { 数据对象V:v是具有相同特性的数据元素的集合,称为顶点集。 数据关系 R:R={VR};VR={<v,w>|v,w∈V 且 P(v,w), <v,w>表示从v到w的弧, 谓词P(v,w)定义了弧<v,w>的意义或信息} 基本操作P: }

  19. 基本操作 CreatGraph(&G, V, VR) // 按定义(V, VR) 构造图 DestroyGraph(&G): // 销毁图 LocateVex(G, u); // 若G中存在顶点u,则返回该顶点在 图中“位置”;否则返回其它信息。 GetVex(G, v);// 返回 v 的值。 PutVex(&G, v, value);// 对 v 赋值value。

  20. 基本操作 FirstAdjVex(G, v); // 返回 v 的“第一个邻接点” 。若该顶点 //在 G 中没有邻接点,则返回“空”。 NextAdjVex(G, v, w); // 返回 v 的(相对于 w 的) “下一个邻接点”。若 w 是 v 的最后一个邻接点,则返回“空”。

  21. 基本操作 InsertVex(&G, v); //在图G中增添新顶点v。 DeleteVex(&G, v); // 删除G中顶点v及其相关的弧。 InsertArc(&G, v, w); // 在G中增添弧<v,w>,若G是无向的, //则还增添对称弧<w,v>。 DeleteArc(&G, v, w); //在G中删除弧<v,w>,若G是无向的, //则还删除对称弧<w,v>。

  22. DFSTraverse(G, v, Visit()) //从顶点v起深度优先遍历图G,并对每个顶点调用函数Visit一次且仅一次。 BFSTraverse(G, v, Visit()) //从顶点v起广度优先遍历图G,并对每个顶点调用函数Visit一次且仅一次。

  23. 7.2 图的存储结构 图的四种常用的存储形式: • 邻接矩阵和加权邻接矩阵(labeled adjacency matrix) • 邻接表 • 十字链表 • 邻接多重表

  24. 一、(加权)邻接矩阵(labeled adjacency matrix) 设图 G= <V, E>是一个有 n 个顶点的图,则图的邻接矩阵是一个二维数组 G.arcs[n][n],定义:

  25. 无向图G1 有向图G2

  26. 一、(加权)邻接矩阵(continue) 从邻接矩阵中可以反映图的许多特征: • 无向图 (1) 对称矩阵(可采用压缩存储); (2) 每一行(或列)1的个数是该顶点的度; (3) 主对角线全为0(简单图);

  27. 一、(加权)邻接矩阵(continue) • 有向图 (1) 每一行1的个数是该顶点的出度; (2) 每一列1的个数是该顶点的入度; (3) 主对角线全为0(简单图); • 有向图的邻接矩阵不一定对称。

  28. Wij <vi, vj> 或(vi, vj)∈VR G.arcs[ i ][ j ]= ∞ 无边(弧) N 5 v1 v2 4 8 3 7 9 v3 v6 6 1 5 v4 v5 5 一、(加权)邻接矩阵(continue) 网络的邻接矩阵 定义为: 以有向网为例: 顶点表: (v1 v2v3 v4 v5 v6 ) 邻接矩阵: ∞5∞ 7∞∞ ∞∞4∞∞∞ 8∞∞∞ ∞9 ∞∞ 5 ∞∞6 ∞∞∞ 5∞∞ 3∞∞ ∞1∞ N.Edge =

  29. 一、(加权)邻接矩阵(continue) 容易实现图的操作,如:求某顶点的度、判断顶点之间是否有边(弧)、找顶点的邻接点等等。 n个顶点需要n*n个单元存储边(弧);空间效率为O(n2)。 对稀疏图而言尤其浪费空间。 邻接矩阵法优点: 邻接矩阵法缺点:

  30. 用邻接矩阵表示的图的存储表示(P161) #define INFINITY INT_MAX #define MAX_VERTEX_NUM 20 typedef enum{DG, DN,UDG,UDN} GraghKind; typedef struct ArcCell { // 弧的定义 VRType adj; // VRType是顶点关系类型。 // 对无权图,用1或0表示相邻否; // 对带权图,则为权值类型。 InfoType *info; // 该弧相关信息的指针 } ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

  31. 用邻接矩阵表示的图的存储表示(continue) typedef struct { // 图的定义 VertexType vexs[MAX_VERTEX_NUM];// 顶点信息 AdjMatrix arcs; // 弧的信息 int vexnum, arcnum; // 顶点数,弧数 GraphKind kind; // 图的种类标志 } MGraph;

  32. 例:用邻接矩阵生成无向网的算法(参见教材P162)例:用邻接矩阵生成无向网的算法(参见教材P162) Status CreateUDN(Mgraph &G){//用邻接矩阵表示 return OK; } for(k=0;k<G.arcnum;++k){ //给弧赋初值(循环次数=弧数) scanf(&v1, &v2, &w); i=LocateVex(G,v1); j=LocateVex(G,v2); //找到两顶点在矩阵中的位置(n次) G.arcs[i][j].adj=w; //输入对应权值 If(IncInfo) Input(*G.arcs[i][j].info); G.arcs[j][i] = G.arcs [i] [j]; //无向网是对称矩阵 } scanf(&G.vexnum, &G.arcnum, &IncInfo); //输入总顶点数,总弧数和信息 for(i=0;i<G.vexnum,;++i) scanf(&G.vexs[i] );//输入顶点值,存入一维向量中 for(i=0; i<G.vexnum; ++i) //对邻接矩阵n*n个单元初始化,adj=∞,info=NULL for(j=0;j<G.vexnum;++j) G.arcs[i][j]={INFINITY, NULL}; 对于n个顶点e条弧的网, 建网时间效率 = O(n2+n+e*n)

  33. 图的部分操作在邻接矩阵上的实现 int firstAdjVex(Mgraph G, int v) { //返回顶点v的第一个邻接点,G为无向图 for (k=0;k<G.vexnum; k++) if (G.adj [v][k]>0 ) break; if (k>=G.vexnum) k= -1; // 无邻接点 return k; }// end firstAdjVex( )

  34. 二、 邻接表 (Adjacency List) v2 v1 3 1 ^ v3 4 4 2 2 0 0 ^ ^ v4 v4 v5 4 3 2 3 1 1 ^ ^ • 无向图的邻接表 为每个顶点建立一个单链表,第i个单链表中的结点表示与顶点vi相邻的顶点 注:邻接表不唯一,因各个边结点的链入顺序是任意的。

  35. data adjvex adjvex data firstarc nextarc nextarc firstarc 二、 邻接表 (Adjacency List) 头结点: data: 结点的数据域,保存结点的数据值。 firstarc: 结点的指针域,给出自该结点出发的的第一条边 的边结点的地址。 表结点: adjvex: 该边或弧所指向的顶点的位置. nextarc: 指向下一条边或弧的指针.

  36. v2 v1 3 1 ^ v3 4 4 2 2 0 0 ^ ^ v4 v4 v5 3 4 3 2 1 1 ^ ^ 二、 邻接表 (Adjacency List) • 在无向图的邻接表中,如何求每个顶点的度? 第 i个链表中的结点个数是顶点 i 的度 • 若顶点数为n,边数为e时,则在无向图中共需多少 个结点? n个头结点,2e个表结点

  37. V1 V2 3 ^ v2 v1 V1 2 1 ^ V3 0 ^ V2 ^ V4 0 ^ 3 ^ V3 v3 v4 2 ^ V4 0 ^ • 有向图的邻接表和逆邻接表 • 在有向图的邻接表中,第 i个单链表链接的边都是顶点 i发出的边。也叫做出边表。 • 在有向图的逆邻接表中,第 i个单链表链接的边都是进入顶点i的边。也叫做入边表。 邻接表(出边) 逆邻接表(入边) 0 1 2 3 0 1 2 3 用邻接表表示有向图时,若不考虑逆邻接表,只需 n 个顶点结点,e 个边结点。

  38. 网络 (带权图) 的邻接表 带权图的边结点中保存该边上的权值 cost

  39. adjvex info nextarc 邻接表表示的图的存储结构(P163) //边结点定义 typedef struct ArcNode { int adjvex; // 该弧所指向的顶点的位置 struct ArcNode *nextarc; // 指向下一条弧的指针 InfoType *info; // 该弧相关信息的指针 } ArcNode;

  40. data firstArc 邻接表表示的图的存储结构(P163) //头结点定义 typedef struct VNode { VertexType data; // 顶点信息 ArcNode *firstarc; // 指向第一条依附该顶点的弧 } VNode, AdjList[MAX_VERTEX_NUM];

  41. 邻接表表示的图的存储结构(P163) //图的定义 typedef struct { AdjList vertices; int vexnum, arcnum; int kind; // 图的种类标志 } ALGraph;

  42. 图的操作在邻接连表的上的实现 int firstAdjVex(ALGraph ghead ,int v) { return ghead[v]->firstArc.adjvex; }// end firstAdjVex( ) int nextAdjVex(ALGraph ghead,int v, int w) { p=ghead[v]->firstArc; while (p&&p->adjvex!=w) p=p->next; if (!p) return 0; else return p->next->adjvex; }// end nextAdjVex( ) 找某顶点的所有邻接点的时间复杂度是O(e)

  43. 如何建立邻接表(以有向图为例) • 算法思想: • 首先将邻接表表头数组初始化,vertex域初始化为i,firstarc初始化为NULL; • 然后对读入的每一条弧<i,j>,产生一个表结点,adjver域置为j,并将结点链接到邻接表的第i个链表中。

  44. 算法如下: Void GreatAdjList(ALGraph &G) { ArcNode *p; sacnf(“%d%d”,&n,&e); G.vexnum=n; G.arcnum=e; for(i=0; i<n; i++) { G.vertices[i].vertex=i; G.vertices[i].firstarc=NULL;} for(k=0; k<e; k++){ scanf(i,j); p=(ArcNode *)malloc(sizeof(ArcNode)); p->adjvex=j; p->nextarc=G.vertices[i].firstarc; G.vertices[i].firstarc=p;} }// GreatAdjList

  45. 讨论:邻接表与邻接矩阵的比较 1. 联系:都可以用来存储有向图和无向图;邻接表中每个链表对应于邻接矩阵中的一行,链表中结点个数等于一行中非零元素的个数。 2. 区别: ①邻接矩阵是顺序结构,邻接表是链式结构 ②对于任一确定的无向图,邻接矩阵是唯一的(行列号与顶点编号一致),但邻接表不唯一(链接次序与顶点编号无关)。 邻接矩阵的空间复杂度为O(n2),而邻接表的空间复杂度为O(n+e)。 邻接矩阵多用于稠密图的存储(e接近n(n-1)/2);而邻接表多用于稀疏图的存储(e<<n2)

  46. 三、 邻接多重表 (无向图的一种存储结构) • 在无向图的邻接表中,一条边出现两个单链表中.浪费空间,也给某种操作带来了困难。 • 在邻接多重表中,每一条边只有一个结点(称边结点)为有关边的处理提供了方便。

  47. 三、 邻接多重表 (无向图的一种存储结构) mark ivex jvex ilink jlink • 边结点的结构 Ebox: 其中: mark是记录是否处理过的标记; ivex和jvex是依附于该边的两顶点位置。 ilink域指向下一条依附于顶点ivex的边; jlink指向下一条依附于顶点jvex的边。 需要时还可设置一个存放与该边相关的权值的域cost。

  48. 三、 邻接多重表 (无向图的一种存储结构) data Firstarc 顶点结点的结构: • 其中: data存放与该顶点相关的信息; Firstarc 是指示第一条依附于该顶点的边的指针。 存储顶点信息的结点表以顺序表方式组织.在邻 接多重表中,所有依附于同一个顶点的边都链接 在同一个单链表中。从顶点 i出发, 可以循链找到 所有依附于该顶点的边,也可以找到它的所有邻 接顶点。 VexBox:

  49. 三、 邻接多重表 (无向图的一种存储结构) 4 1 2 4 2 1 2 3 0 3 0 1 0 a 例 b 1 a b 2 c c 3 d d e 4 e ^ ^ ^ ^ ^

  50. 四、十字链表(有向图的一种存储结构) • 可以把十字链表看成是将有向图的邻接表和逆 邻接表这两个表结合起来而得到的一种链表。 • 在十字链表中,有向图中每一条弧对应一个结点(称弧结点) • 每一个顶点也对应一个结点(称顶点结点)。

More Related