收藏 分享(赏)

第8章-图算法.ppt

上传人:jinchen 文档编号:9863158 上传时间:2019-09-12 格式:PPT 页数:75 大小:1.26MB
下载 相关 举报
第8章-图算法.ppt_第1页
第1页 / 共75页
第8章-图算法.ppt_第2页
第2页 / 共75页
第8章-图算法.ppt_第3页
第3页 / 共75页
第8章-图算法.ppt_第4页
第4页 / 共75页
第8章-图算法.ppt_第5页
第5页 / 共75页
点击查看更多>>
资源描述

1、1,第八章:图算法,2,图是由一个顶点集 V 和一个弧集 R构成的数据结构。Graph = (V , R ) 其中,VR| v,wV 且 P(v,w)表示从 v 到 w 的一条弧,并称 v 为弧头,w 为弧尾。谓词 P(v,w) 定义了弧 的意义或信息。,图的结构定义:,图的定义,3,一、图的数组(邻接矩阵)存储表示,B,A,C,D,F,E,定义:矩阵的元素为,图的存储表示,4,有向图的邻接矩阵为非对称矩阵,A,B,F,C,E,图的数组(邻接矩阵)存储表示,5,typedef struct ArcCell / 弧的定义VRType adj; / VRType是顶点关系类型。/ 对无权图,用1或

2、0表示相邻否;/ 对带权图,则为权值类型。InfoType *info; / 该弧相关信息的指针 ArcCell, AdjMatrixMAX_VERTEX_NUMMAX_VERTEX_NUM;,6,typedef struct / 图的定义VertexType / 顶点信息vexsMAX_VERTEX_NUM; AdjMatrix arcs; / 弧的信息 int vexnum, arcnum; / 顶点数,弧数 GraphKind kind; / 图的种类标志 MGraph;,7,0 A 1 4 1 B 0 4 5 2 C 3 5 3 D 2 5 4 E 0 1 5 F 1 2 3,B,A,

3、C,D,F,E,二、图的邻接表存储表示,8,1 4,2,3,0 1,2,0 1 2 3 4,ABCDE,有向图的邻接表,A,B,E,C,D,可见,在有向图的邻接表中不易找到指向该顶点的弧。,9,A,B,E,C,D,有向图的逆邻接表,A B C D E,3,0,3,2,0,0 1 2 3 4,在有向图的邻接表中,对每个顶点,链接的是指向该顶点的弧。,10,typedef struct ArcNode int adjvex; / 该弧所指向的顶点的位置struct ArcNode *nextarc; / 指向下一条弧的指针InfoType *info; / 该弧相关信息的指针 ArcNode;,a

4、djvex nextarc info,弧的结点结构,11,typedef struct VNode VertexType data; / 顶点信息ArcNode *firstarc; / 指向第一条依附该顶点的弧 VNode, AdjListMAX_VERTEX_NUM;,data firstarc,顶点的结点结构,12,typedef struct AdjList vertices;int vexnum, arcnum; int kind; / 图的种类标志 ALGraph;,图的结构定义,13,三、有向图的十字链表存储表示,14,三、有向图的十字链表存储表示,弧的结点结构,弧尾顶点位置 弧

5、头顶点位置 弧的相关信息,指向下一个有相同弧尾的结点,指向下一个有相同弧头的结点,typedef struct ArcBox / 弧的结构表示int tailvex, headvex; InfoType *info;struct ArcBox *hlink, *tlink; VexNode;,15,顶点的结点结构,顶点信息数据,指向该顶点的第一条入弧,指向该顶点的第一条出弧,typedef struct VexNode / 顶点的结构表示VertexType data;ArcBox *firstin, *firstout; VexNode;,16,typedef struct VexNode

6、xlistMAX_VERTEX_NUM; / 顶点结点(表头向量) int vexnum, arcnum;/有向图的当前顶点数和弧数 OLGraph;,有向图的结构表示(十字链表),17,四、无向图的邻接多重表存储表示,18,四、无向图的邻接多重表存储表示,typedef struct Ebox VisitIf mark; / 访问标记int ivex, jvex;/该边依附的两个顶点的位置struct EBox *ilink, *jlink; InfoType *info; / 该边信息指针 EBox;,边的结构表示,19,typedef struct / 邻接多重表VexBox adjmu

7、listMAX_VERTEX_NUM;int vexnum, edgenum; AMLGraph;,顶点的结构表示,typedef struct VexBox VertexType data;EBox *firstedge; / 指向第一条依附该顶点的边 VexBox;,无向图的结构表示,20,图的遍历,从图中某个顶点出发游历图,访遍 图中其余顶点,并且使图中的每个顶点 仅被访问一次的过程。,深度优先搜索,广度优先搜索,遍历应用举例,21,从图中某个顶点V0 出发,访问此顶点,然后依次从V0的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和V0有路径相通的顶点都被访问到。,一、深度优

8、先搜索遍历图,连通图的深度优先搜索遍历,22,深度优先搜索遍历实例,23,V,w1,SG1,SG2,SG3,W1、W2和W3 均为 V 的邻接点,SG1、SG2 和 SG3 分别为含顶点W1、W2和W3 的子图。,访问顶点 V : for (W1、W2、W3 )若该邻接点W未被访问,则从它出发进行深度优先搜索遍历。,w2,w3,w2,24,从上页的图解可见:,1. 从深度优先搜索遍历连通图的过程类似于树的先根遍历;,解决的办法是:为每个顶点设立一个 “访问标志 visitedw”。,2. 如何判别V的邻接点是否被访问?,25,void DFS(Graph G, int v) / 从顶点v出发,

9、深度优先搜索遍历连通图 Gvisitedv = TRUE; VisitFunc(v);for(w=FirstAdjVex(G, v);w!=0; w=NextAdjVex(G,v,w)if (!visitedw) DFS(G, w); / 对v的尚未访问的邻接顶点w/ 递归调用DFS / DFS,26,首先将图中每个顶点的访问标志设为 FALSE, 之后搜索图中每个顶点,如果未被访问,则以该顶点为起始点,进行深度优先搜索遍历,否则继续检查下一顶点。,非连通图的深度优先搜索遍历,27,void DFSTraverse(Graph G, Status (*Visit)(int v) / 对图 G

10、作深度优先遍历。VisitFunc = Visit; for (v=0; vG.vexnum; +v) visitedv = FALSE; / 访问标志数组初始化for (v=0; vG.vexnum; +v) if (!visitedv) DFS(G, v);/ 对尚未访问的顶点调用DFS ,28,a,b,c,h,d,e,k,f,g,F F F F F F F F F,T,T,T,T,T,T,T,T,T,a,c,h,d,k,f,e,b,g,a,c,h,k,f,e,d,b,g,访问标志:,访问次序:,例如:,0 1 2 3 4 5 6 7 8,29,二、广度优先搜索遍历图,V,w1,w8,w3

11、,w7,w6,w2,w5,w4,对连通图,从起始点V到其余各顶点必定存在路径。,其中,V-w1, V-w2, V-w8 的路径长度为1;,V-w7, V-w3, V-w5的路径长度为2;,V-w6, V-w4 的路径长度为3。,w1,V,w2,w7,w6,w3,w8,w5,w4,30,从图中的某个顶点V0出发,并在访问此顶点之后依次访问V0的所有未被访问过的邻接点,之后按这些顶点被访问的先后次序依次访问它们的邻接点,直至图中所有和V0有路径相通的顶点都被访问到。,若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。,31,void

12、BFSTraverse(Graph G,Status (*Visit)(int v)for (v=0; vG.vexnum; +v)visitedv = FALSE; /初始化访问标志InitQueue(Q); / 置空的辅助队列Qfor ( v=0; vG.vexnum; +v )if ( !visitedv) / v 尚未访问 / BFSTraverse, ,32,visitedu = TRUE; Visit(u); / 访问u EnQueue(Q, v); / v入队列 while (!QueueEmpty(Q) DeQueue(Q, u); / 队头元素出队并置为ufor(w=Firs

13、tAdjVex(G, u); w!=0; w=NextAdjVex(G,u,w)if ( ! visitedw) visitedw=TRUE; Visit(w);EnQueue(Q, w); / 访问的顶点w入队列 / if / while,33,三、遍历应用举例,1. 求一条从顶点 i 到顶点 s 的简单路径,2. 求两个顶点之间的一条路径长度最短的路径,34,1. 求一条从顶点i到顶点s的简单路径,a,b,c,h,d,e,k,f,g,求从顶点 b 到顶点 k 的一条简单路径。,从顶点 b 出发进行深度优先搜索遍历。,例如:,假设找到的第一个邻接点是a,则得到的结点访问序列为: b a d

14、h c e k f g。,假设找到的第一个邻接点是c,则得到的结点访问序列为:b c h d a e k f g,,35,void DFSearch( int v, int s, char *PATH) / 从第v个顶点出发递归地深度优先遍历图G,/ 求得一条从v到s的简单路径,并记录在PATH中 visitedv = TRUE; / 访问第 v 个顶点Append(PATH, getVertex(v); / 第v个顶点加入路径 for (w=FirstAdjVex(v); w!=0 / 从路径上删除顶点 v ,36,2. 求两个顶点之间的一条路径长度最短的路径,若两个顶点之间存在多条路径,则

15、其中必有一条路径长度最短的路径。如何求得这条路径?,37,a,b,c,h,d,e,k,f,g,因此,求路径长度最短的路径可以基于广度优先搜索遍历进行,但需要修改链队列的结点结构及其入队列和出队列的算法。,深度优先搜索访问顶点的次序取决于图的存储结构,而广度优先搜索访问顶点的次序是按“路径长度”渐增的次序。,38,例如:求下图中顶点 3 至顶点 5 的一条最短路径。,链队列的状态如下所示:,3 1 2 4 7 5,Q.front Q.rear,3,2,1,4,7,5,6,8,9,39,1) 将链队列的结点改为“双链”结点。即 结点中包含next 和prior两个指针;,2) 修改入队列的操作。插

16、入新的队尾结点时,令其prior域的指针指向刚刚出队列的结点,即当前的队头指针所指结点;,3) 修改出队列的操作。出队列时,仅移动队头指针,而不将队头结点从链表中删除。,40,typedef DuLinkList QueuePtr; void InitQueue(LinkQueue e = Q.front-data ,41,最小生成树,假设要在 n 个城市之间建立通讯联络网,则连通 n 个城市只需要修建 n-1条线路,如何在最节省经费的前提下建立这个通讯网?,问题:,构造网的一棵最小生成树,即:在 e 条带权的边中选取 n-1 条边(不构成回路),使“权值之和”为最小。,42,取图中任意一个顶

17、点 v 作为生成树的根,之后往生成树上添加新的顶点 w。在添加的顶点 w 和已经在生成树上的顶点v 之间必定存在一条边,并且该边的权值在所有连通顶点 v 和 w 之间的边中取值最小。之后继续往生成树上添加顶点,直至生成树上含有 n-1 个顶点为止。,普里姆算法的基本思想,43,a,b,c,d,e,g,f,例如:,19,5,14,18,27,16,8,21,3,a,e,12,d,c,b,g,f,7,14,8,5,3,16,21,所得生成树权值和,= 14+8+3+5+16+21 = 67,44,在生成树的构造过程中,图中 n 个顶点分属两个集合:已落在生成树上的顶点集 U 和尚未落在生成树上的顶

18、点集V-U ,则应在所有连通U中顶点和V-U中顶点的边中选取权值最小的边。,一般情况下所添加的顶点应满足条件,45,设置一个辅助数组,对当前VU集中的每个顶点,记录和顶点集U中顶点相连接的代价最小的边:,struct VertexType adjvex; / U集中的顶点序号VRType lowcost; / 边的权值 closedgeMAX_VERTEX_NUM;,46,a,b,c,d,e,g,f,19,5,14,18,27,16,8,21,3,a,e,12,d,c,b,7,a,a,a,19,14,18,14,例如:,e,12,e,e,8,16,8,d,3,d,d,7,21,3,c,5,5,

19、47,void MiniSpanTree_P(MGraph G, VertexType u) /用普里姆算法从顶点u出发构造网G的最小生成树k = LocateVex ( G, u ); for ( j=0; jG.vexnum; +j ) / 辅助数组初始化if (j!=k) closedgej = u, G.arcskj.adj ; closedgek.lowcost = 0; / 初始,Uufor (i=0; iG.vexnum; +i) ,继续向生成树上添加顶点;,48,k = minimum(closedge); / 求出加入生成树的下一个顶点(k)printf(closedgek.

20、adjvex, G.vexsk); / 输出生成树上一条边closedgek.lowcost = 0; / 第k顶点并入U集for (j=0; jG.vexnum; +j) /修改其它顶点的最小边if (G.arcskj.adj closedgej.lowcost)closedgej = G.vexsk, G.arcskj.adj ;,49,具体做法: 先构造一个只含 n 个顶点的子图 SG,然后从权值最小的边开始,若它的添加不使SG 中产生回路,则在 SG 上加上这条边,如此重复,直至加上 n-1 条边为止。,考虑问题的出发点: 为使生成树上边的权值之和达到最小,则应使生成树中每一条边的权值

21、尽可能地小。,克鲁斯卡尔算法的基本思想,50,a,b,c,d,e,g,f,19,5,14,18,27,16,8,21,3,a,e,12,d,c,b,g,f,7,14,8,5,3,16,21,例如:,7,12,18,19,51,算法描述,构造非连通图 ST=( V, );k = i = 0; / k 计选中的边数while (kn-1) +i;检查边集 E 中第 i 条权值最小的边(u,v);若(u,v)加入ST后不使ST中产生回路,则 输出边(u,v); 且 k+; ,52,普里姆算法,克鲁斯卡尔算法,时间复杂度,O(n2),O(eloge),稠密图,稀疏图,算法名,适应范围,比较两种算法,5

22、3,拓扑排序,问题:,假设以有向图表示一个工程的施工图或程序的数据流图,则图中不允许出现回路。,检查有向图中是否存在回路的方法之一,是对有向图进行拓扑排序。,54,拓扑排序,对有向图进行如下操作,按照有向图给出的次序关系,将图中顶点排成一个线性序列,对于有向图中没有限定次序关系的顶点,则可以人为加上任意的次序关系。,由此所得顶点的线性序列称之为拓扑有序序列,55,拓扑排序,56,例如:对于下列有向图,B,D,A,C,可求得拓扑有序序列:A B C D 或 A C B D,拓扑排序,57,对于下列有向图,不能求得它的拓扑有序序列。,因为图中存在一个回路 B, C, D,拓扑排序,58,如何进行拓

23、扑排序,一、从有向图中选取一个没有前驱的顶点,并输出之;,重复上述两步,直至图空,或者图不空但找不到无前驱的顶点为止。,二、从有向图中删去此顶点以及所有以它为尾的弧;,59,取入度为零的顶点v; while (v0) printf(v); +m;w:=FirstAdj(v);while (w0) inDegreew-;w:=nextAdj(v,w);取下一个入度为零的顶点v; if mn printf(“图中有回路”);,算法描述,60,为避免每次都要搜索入度为零的顶点,在算法中设置一个“栈”,以保存“入度为零”的顶点。,CountInDegree(G,indegree);/对各顶点求入度 I

24、nitStack(S); for ( i=0; iG.vexnum; +i)if (!indegreei) Push(S, i);/入度为零的顶点入栈,61,count=0; /对输出顶点计数 while (!EmptyStack(S) Pop(S, v); +count; printf(v);for (w=FirstAdj(v); w; w=NextAdj(G,v,w)-indegree(w); / 弧头顶点的入度减一if (!indegreew) Push(S, w); /新产生的入度为零的顶点入栈 if (countG.vexnum) printf(“图中有回路”),62,求从源点到其余

25、各点的最短路径的算法的基本思想:,依最短路径的长度递增的次序求得各条路径,源点,v1,其中,从源点到顶点v的最短路径是所有最短路径中长度最短者。,v2,最短路径,63,问题描述,给定一个带权有向图D与源点v,求从v到D中其它顶点的最短路径。限定各边上的权值大于或等于0。,Negative-cost cycle,单源最短路径,64,在这条路径上,必定只含一条弧,并且这条弧的权值最小。,下一条路径长度次短的最短路径的特点:,路径长度最短的最短路径的特点:,它只可能有两种情况:或者是直接从源点到该点(只含一条弧); 或者是从源点经过顶点v1,再到达该顶点(由两条弧组成)。,65,其余最短路径的特点:

26、,再下一条路径长度次短的最短路径的特点:,它可能有三种情况:或者是直接从源点到该点(只含一条弧); 或者是从源点经过顶点v1,再到达该顶点(由两条弧组成);或者是从源点经过顶点v2,再到达该顶点。,它或者是直接从源点到该点(只含一条弧); 或者是从源点经过已求得最短路径的顶点,再到达该顶点。,66,求最短路径的迪杰斯特拉算法,1、初始化:S v0 ; distj Edge0j, j = 1, 2, , n-1;2、求出最短路径的长度:distk min disti , i V- S ; S S U k ;3、修改: distimindisti,distk+Edgeki ,对于每一个 i V-

27、S ; 4、判断: 若S = V, 则算法结束,否则转2。,67,求最短路径的迪杰斯特拉算法,一般情况下, Distk = 或者 = + 。,设置辅助数组Dist,其中每个分量Distk 表示 当前所求得的从源点到其余各顶点 k 的最短路径。,68,1)在所有从源点出发的弧中选取一条权值最小的弧,即为第一条最短路径。,2)修改其它各顶点的Distk值。 假设求得最短路径的顶点为u, 若 Distu+G.arcsukDistk 则将 Distk 改为 Distu+G.arcsuk。,V0和k之间存在弧,V0和k之间不存在弧,其中的最小值即为最短路径的长度。,69,迪杰斯特拉算法,void Sho

28、rtestPath_DIJ(MGraph G,int v0,PathMatrix / 初始化,v0顶点属于S集,/- 开始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集 -for (i=1; iG.vexnum; +i) / 其余G.vexnum-1个顶点min = INFINITY; / 当前所知离v0顶点的最近距离for (w=0; wG.vexnum; +w)if (!finalw) / w顶点在V-S中if (Dwmin) v = w; min = Dw; / w顶点离v0顶点更近finalv = TRUE; / 离v0顶点最近的v加入S集for (w=0; wG.vexnu

29、m; +w) / 更新当前最短路径及距离if (!finalw / Pw = Pv+w/if/for / ShortestPath_DIJ,70,求每一对顶点之间的最短路径,弗洛伊德算法的基本思想是:,从vi到vj的所有可能存在的路径中,选出一条长度最短的路径。,若存在,则存在路径vi,vj/ 路径中不含其它顶点 若,存在,则存在路径vi,v1,vj/ 路径中所含顶点序号不大于1 若vi,v2, v2,vj存在,则存在一条路径vi, , v2, vj/ 路径中所含顶点序号不大于2,71,Floyd 算法例图,72,Floyd 算法思想,定义k-path 为任意一条从顶点v到u的,中间顶点序号小

30、于k的路径。 0-path 即为直接地从v到u的边。 定义Dk(v, u)为从v到u的长度最小的k-path 假设我们已知从v到u的最短k-path path,则最短的(k+1)-path 经过,或不经过顶点k 如果它经过顶点k,短则最短(k+1)-path 的一部分是从v到k的最短k-path ,另一部分是从k到u的最短k-path 。 否则,我们保持其值为最短k-path不变。,73,实例及求解,74,Floyd 算法特点,Floyd 算法仅通过一个三重循环检查了所有的可能性。 下面给出Floyd 算法的实现。在算法结束时,D数组存储了所有成对顶点间的最短路径长度。 显然这个算法的时间代价为(|V|3) Floyd 算法也是一种动态规划法,75,Floyd 算法,void ShortestPath_FLOYD(MGraph G, PathMatrix P, DistancMatrix /if / ShortestPath_FLOYD,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报