首页计算机计算机基础数据结构与算法 07 第7章 图.pptx

07 第7章 图.pptx

页数:103页文件大小:701.4 KB来源: 数据结构与算法ppt课件

本课件讲解图的定义与术语,给出数组表示法、邻接表、十字链表与邻接多重表等存储结构,展开深度优先与广度优先遍历,随后讲最小生成树的普里姆与克鲁斯卡尔算法,以及拓扑排序、关键路径与最短路径的求解。

第七章图章节封面页,标示本章讲图的定义术语、存储结构、遍历、连通性、有向无环图与最短路径
图结构概述页,说明图中元素之间存在任意关系,GIS中的道路网与通讯网都可用图表示
内容提要页,列出图的定义和术语、存储结构、遍历、连通性问题、有向无环图应用与最短路经
查看本课件的文字版(共 103 页,供检索与复制)

第1页:第七章图

第七章图

第2页:图的概述

线性结构——线性关系

  • 树结构——层次关系,非线性结构
  • 图(网)结构——非线性结构,元素之间存在任意关系,即任意两个元素之间都可能存在关系。GIS中,道路网、通讯网
  • 本章目的:熟悉图的有关术语和概念、掌握图的四种存储结构、掌握图的两种遍历方法、理解求图的最小生成树的两种算法,掌握关键路径和最短路径的求解算法

第3页:第七章内容提要

本章内容:1.图的定义和术语2.图的存储结构3.图的遍历4.图的连通性问题5.有向无环图及其应用6.最短路经.本章重点

第4页:第一节图的定义和术语

第一节图的定义和术语

第5页:图的定义

硕图(Graph):图G是由两个集合V(G)和E(G)组成的,记为G=(V,E),其中:V(G)是顶点的非空有限集E(G)是边的有限集合,边是顶点的无序对或有序对V2V1V3V4V2V1V4V5V3G1G2

第6页:有向图的定义

有向图:有向图G是由两个集合V(G)和E(G)组成的图,其中:V(G)是顶点的非空有限集V3V4E(G)是有向边(也称弧)的有限集合,弧是顶点的有序对,记为<v,w>,v,w是顶点,v为弧尾,w为弧头V1V2G1

第7页:无向图的定义

无向图:无向图G是由两个集合V(G)和E(G)组成的图,其中:V(G)是顶点的非空有限集E(G)是边的有限集合,边是顶点的无序对,记为(v,w)或(w,v),并且(v,w)=(w,v)V2V1V4V5V3G2

第8页:有向图与无向图举例

例如1245163G1图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>}例如21573246G2图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)}

第9页:完全图与稀疏图

完全图:对于有n顶点的无向图,边E的取值范围是0~n(n-1)/2,当n个顶点的无向图有n(n-1)/2条边时称为完全图

  • 有向完全图:对于有n顶点的无向图,边E的取值范围是0~n(n-1),当n个顶点的有向图有n(n-1)条边时称为有向完全图
  • 稀疏图:有很少条边或弧(<nlogn)的图,反之称为稠密图
  • 权:与图的边或弧相关的数(长度、费用、运行时间)
  • 网:带权的图(道路网)132213有向完全图无向完全图

第10页:子图与邻接点

子图:假设有两个图G=(V,{E})和G’=(V’,{E’}),如果V’V,E’E,则称G’为G的子图

  • 邻接点:如果边(v,u)E,则称顶点v和u互为邻接点
  • 边(v,u)依附顶点v和u、或边(v,u)和顶点v和u相关联356245136图与子图

第11页:顶点的度

顶点的度

  • 无向图中,顶点的度为与每个顶点相连的边数
  • 有向图中,顶点的度分成入度与出度
  • 入度:以该顶点为头的弧的数目
  • 出度:以该顶点为尾的弧的数目245163G4顶点2入度:1顶点4入度:1出度:3出度:01573624G3顶点5的度:3顶点2的度:4

第12页:路径与回路

路径:路径是从顶点V到V’所经过的顶点系列{V=Vi,0,Vi,1,……Vi,m=V’},其中(Vi,j-1,Vij)E,(1<jn)

  • 路径长度:路径上边的数目或沿路径各边权值之和
  • 回路:第一个顶点和最后一个顶点相同的路径
  • 简单路径:顶点序列中顶点不重复出现的路径
  • 简单回路:除了第一个顶点和最后一个顶点外,其余顶点不重复出现的回路124536路径:1,2,3,5,6,3路径长度:5简单路径:1,2,3,5回路:1,2,3,5,6,3,1简单回路:3,5,6,3

第13页:连通与强连通

DEGHKCFIJLMCFJAABBLMDEIGHK

  • 强连通图:有向图中,如果对每一对Vi,VjV,ViVj,从Vi到Vj和从Vj到Vi都存在路径连通图
  • 连通:无向图中,从顶点V到顶点U有一条路径,则说V和U是连通的
  • 连通图:图中任意两个顶点都是连通的
  • 连通分量:非连通图的每一个连通部分连通分量无向图非连通图21强连通图3

第14页:连通分量示意图

强连通图356245136非连通图连通分量连通图245136

第15页:生成树与生成森林

生成树:一个连通图的生成树是一个极小连通子图,它包含有图中的全部顶点(n个),但只有足以构成一棵树的n-1条边

  • 生成森林:如果一个有向图恰有一个顶点的入度为0,其余顶点的入度为均为1,则是一棵有向树;而一个有向图的生成森林由若干棵有向树组成,含有图中的全部顶点,但只有构成若干棵不相交的有向树的弧FEABCDCDFBEA有向图及其生成森林

第16页:第二节图的存储结构

第二节图的存储结构

第17页:图的存储结构概览

数组表示法

  • 邻接表
  • 十字链表
  • 邻接多重表返回

第18页:数组表示法

(1)数组表示法

  • 用两个数组分别存储图的顶点信息和顶点之间关系的信息
  • //图的数组存储表示
  • #defineINFINITYINT_MAX//最大值
  • #defineMAX_VERTEX_NUM20//最大顶点数
  • #typedefenum{DE,DN,AG,AN}GraphKind//{有向图,有向网,无向图,无向网}
  • TypedefstructArcCell{VRTypeadj;//顶点关系类型,取值1或0(图)、或权值(网)infoType*info;
  • }ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]

第19页:邻接矩阵的度计算

TypedefstructVNode{VertexType点向量AdjMatrixvexs[MAX_VERTEX_NUM];//顶arcs;//邻接矩阵intvexnum,arcnum;GraphKindkind;

  • }Mgraph
  • 无向图:顶点Vi的度是i行或i列非零元素个数
  • 有向图:行元素之和为顶点的出度,列元素之和为顶点的入度

第20页:邻接矩阵的定义

0,其它

邻接矩阵
表示顶点间相联关系的矩阵定义:设G=(V,E)是有n1个顶点的图,G的邻接矩阵A是具有以下性质的n阶方阵A[i,j]1,若(vi,vj)或vi,vjE(G)15324G200110101010100111010@@@@@@0@1@0@1@0G12413010000000011@0@0@1@@@@@0邻接矩阵

第21页:邻接矩阵的特点

特点:0,其它

  • 无向图的邻接矩阵对称,可压缩存储;有n个顶点的无向图需存储空间为n(n+1)/2
  • 有向图邻接矩阵不一定对称;有n个顶点的有向图需存储空间为n²
  • 无向图中顶点Vi的度TD(Vi)是邻接矩阵A中第i行元素之和
  • 有向图中,O顶点Vi的出度是A中第i行元素之和
  • 顶点Vi的入度是A中第i列元素之和
  • 网络的邻接矩阵可定义为:A[i,j]ij,若(vi,vj)或vi,vjE(G)

第22页:网络的邻接矩阵

61857030040024208160@@@@@@0@5@7@0@3例如网络的邻接矩阵4537152318642返回

第23页:邻接表存储表示

图中每个顶点建立一个单链表,第i个单链表中的结点表示依附顶点Vi的边

  • 每个链表设置一个头结点
  • 头结点以顺序结构存储(有点类似树的孩子表示法)
  • //图的邻接表存储表示
  • #defineMAX_VERTEX_NUM20
  • TypedefstructArcNode{intadjvex;//该弧所指向的顶点(顶点将被多次存储)Structut*nextarc;//下一条弧InfoType*info;//与该弧相关信息
  • }ArcNode;(2)邻接表

第24页:邻接表的类型定义

Typedefstruct{VertexTypeArcNodedata;//顶点信息*firstarc;

  • }VNode,AdjList[MAX_VERTEX_NUM]
  • Typedefstruct{AdjListvertices;intvexnum,arcnum;intkind;//图的种类标志
  • }ALGgraph

第25页:邻接表举例

G1bdacaecbdG21234acdb32^^^4^112344212abcde^^^5435^15323^邻接表举例

第26页:无向图的邻接表应用程序

无向图的邻接表生成和显示应用程序

第27页:邻接表的特点

例G1dabc1234acdb^4^1^1^3返回

  • 特点
  • 无向图中顶点Vi的度为第i个单链表中的结点数
  • 有向图中
  • 顶点Vi的出度为第i个单链表中的结点个数
  • 顶点Vi的入度为整个单链表中邻接点域值是i的结点个数,求入度必须遍历整个邻接表
  • 在稀疏的情况下邻接表比邻接矩阵节省存储空间
  • 为确定顶点的入度可以建立一个逆邻接表:以Vi为头的弧的表
  • 逆邻接表:有向图中对每个结点建立以Vi为头的弧的表

第28页:十字链表

(3)十字连表

  • 是有向图的另一种链式存储结构,可以看成是将邻接表和逆邻接表结合起来的一种链表
  • 每条弧、每个结点分别对应一个弧结点和顶点结点
  • 适合有向图表示
  • //有向图的十字接表存储表示
  • #defineMAX_VERTEX_NUM20
  • TypedefstructArcBox{inttailvex,headvex;//弧头、忽尾顶点的位置structArcBox*hlink,*tlink;//分别指向弧头和弧尾相同的弧的链域infoType*info;//与该弧相关信息东华理工
  • 学院}A程r朋c根Box;firstoutfirstindatainfotlinkhlinkheadvextailvex

第29页:十字链表的结点结构

(3)十字连表(续)

  • TypedefstructVexNode{VertexTypedata;//顶点信息ArcBox*firstin,*firstout;//第一条入弧和出弧
  • }VexNode
  • Typedef struct{VerNodexList[MAX_VERTEX_NUM];//表头向量intvexnum,arcnum;
  • }OLGraph
  • 该结构容易找到结点的出度和入度
  • 横向串连尾相同的弧段,即横向结点数为出度
  • 纵向串连头相同的弧段,即纵向结点数为入度

第30页:十字链表举例

例bdacabcd12341312314241^^^^^^34^^43入度,逆邻接表十字链表举例尾,头返回(3)十字连表(续)

第31页:邻接多重表

(4)邻接多重表

  • 在(无向)图的邻接表的存储结构中每条边(Vi,Vj)的两个顶点分别在第i个和第j个链表中,容易出现结点属性不一致的问题,给操作带来麻烦
  • 以边作为基本存储单元
  • 邻接多重表是无向图的另一种存储结构;当需要找到表示同一条边的两个顶点时,邻接多重表比较方便datafirstedgeinfojlinkjvexilinkivexmark

第32页:邻接多重表的结点结构

//无向图的邻接多重表存储表示

  • #defineMAX_VERTEX_NUM20
  • #typedefenum{unvisted,visited}VisitIf
  • TypedefstructEBox{VisitIFmark;//是否被扫索intivex,jvex;//依附该边的两个顶点StructEBox*ilink,*jlink;//分别指向依附这两点的下一条边InfoType*info;//与该边相关信息
  • }EBox;

第33页:邻接多重表的类型定义

TypedefstructVexBox{VertexTypedata;//顶点信息*firstedge;//第一条依附该顶点的边ArcBox

  • }VexBox
  • Typedefstruct{VerBoxadjmuList[MAX_VERTEX_NUM];intvexnum,edgenum;//无向图的当前顶点数和边数
  • }AMLGraph;

第34页:邻接多重表举例

例aebdacd12b345e123432521^4^^5^3^邻接多重表返回e2e3e1e4e5ce6e1e2e4e3e5e6

第35页:第三节图的遍历

第三节图的遍历

第36页:图的遍历概念

图的遍历:从图中某个顶点出发,访遍图中其余结点,且使每个顶点仅被访问一次

  • 深度优先搜索(DepthFirstSearch,DSF)
  • 广度优先搜索(BreadthFirstSerach,BFS)返回

第37页:深度优先搜索

(1)深度优先搜索

  • 类似树的先根遍历
  • //算法7.4和7.5使用的全局变量-----
  • Booleanvisited[MAX]
  • Status(*visitFunc)(intv);//访问标志数组,避免重复访问//函数变量
  • VoidDESTraverse(GraphG,status(*visit)(intv)){//对图G作深度优先遍历visitFunc=visit//使用全局变量VisitFunc,使DFS不必设函数指针参数for( v=0,v<G.vexnum;++v) visited[v]=FALSE;//访问标志数组初始化for(v=0;v<G.vexnum;++v)if(!visited[v])DFS(G,v);//对尚未访问的顶点调用DFS
  • }返回

第38页:深度优先搜索递归算法

//从第v个顶点出发递归地深度优先遍历图G

  • //采用邻接表表示voidDFS(GraphG,intv){Visited[v]=TRUE;VisitFunc(v);//该问第v个顶点for(w=FistAdjVex(G,v);w;w=NetAdjVex(G,v,w))if(!visited[w])DFS(G,w);顶点w递归调用DFS
  • }//对v的尚未访问的邻接

第39页:无向图的深度优先遍历示例

V1V2V3V4V5V6V7V8例12341342vexdatafirstarc2783^^^adjvexnext56785641^51282^6787365^^3^4深度遍历:V1V3V7V6V2V5V8V4深度优先搜索(无向图)

第40页:有向图的深度优先遍历示例

V1V2V3V4V5V6V7V8例1234vexdatafirstarc2783^^^adjvexnext567864^82^7^123456^7^8深度遍历:V1V3V7V6V2V4V8V5深度优先搜索(有向图)

第41页:深度优先遍历顺序的比较

V1V2V3V4V5V6V7V8深度遍历:V1V2V4V8V5V6V3V7深度优先搜索从上述3个实例可以看出:深度遍历结点顺序与邻接表存储的具体值有关

第42页:广度优先搜索

(2)广度优先搜索

  • 类似于树的按层次遍历的过程
  • 遍历过程:以v为起始点,由近至远,依次访问和v有路径且长度为1,2,…的顶点,为此,需附设队列以存储已被访问的路径长度为1,2,…的顶点
  • voidBFSTraverse(GraphG,Status(*Visit)(intv)){for(v=0;v<G.vexnum;++v)visited[v]=FALSE;InitQueue(Q);//置空的辅助对列Qfor(v=0;v<G.vexnum;++v)if(!visited[v]){//v尚未访问Visited[v]=TURE;Visit(v);EnQueue(Q,v);//v入队列返回

第43页:广度优先搜索算法续

while(!QueueEmpty(Q))DeQueue(Q,u);{//对头元素出队并置为ufor(w=firstAdjvex(G,u);w;w=NextAdjVex(G,u,w)if(!visited[w]){//w为u的尚未访问的邻接顶点Visited[w]=TRUE;Visit(w);EnQueue(Q,w);}//while}//if}//if

  • }//BFSTraverse//使用辅助对列Q和访问标志数组visited

第44页:广度优先搜索示例

V1V2V3V4V5V6V7V8例例V1V3V2V5V6V4V8V7广度遍历:V1V2V3V4V5V6V7V8广度遍历:V1V2V3V4V5V6V7V8广度优先搜索

第45页:广度优先搜索示例二

V1V2V3V4V5V6V7V8例广度遍历:V1V2V3V4V6V7V8V5广度优先搜索

第46页:广度优先搜索过程演示

例123451234vexdatafirstarc5543^^adjvexnext1234555^1^1143^22f1012345r遍历序列:14f012345r遍历序列:1443f012345r遍历序列:143广度优先搜索

第47页:广度优先搜索过程演示续

例123451234vexdatafirstarc5543^^adjvexnext1234555^1^1143^22432f012345r遍历序列:143232f012345r遍历序列:1432325f012345r遍历序列:14325广度优先搜索

第48页:广度优先搜索过程演示续二

25f012345r遍历序列:143255f012345r遍历序列:14325f012345r遍历序列:14325例123451234vexdatafirstarc5543^^adjvexnext1234555^1^1143^22广度优先搜索

第49页:图的遍历实例

实例

第50页:图的遍历算法应用程序

图的遍历算法应用程序

第51页:第四节图的连通性问题

第四节图的连通性问题

第52页:图的连通性问题内容

目的:利用遍历图的算法求解图的连通性问题

  • 无向图的连通分量和生成树
  • 最小生成树返回

第53页:无向图的连通分量和生成树

(1)无向图的连通分量和生成树

  • 对连通图,从任意一个顶点出发可以进行深度或广度优先搜索遍可访问图中所有的点;对非连通图,则需要从多个顶点出发进行搜索
  • 每次搜索所访问的顶点顶点集加上所有依附于这些顶点的边,便构成了图的连通分量
  • 一个连通图的生成树是一个极小连通子图,它含有图中的全部顶点,但只有足以构成一棵树的n-1条边
  • 深度优先搜索得到的生成树为深度优先生成树
  • 广度优先搜索得到的生成树为广度优先生成树
  • 对非连通图,可得到连通分量,各个分量的生成树构成该非连通图的生成森林

第54页:深度与广度优先生成树

返回V1V2V3V4V5V6V7V8G4V1V2V3V4V5V6V7V8广度优先生成树V1V2V4V3V7V6V8V5深度优先生成树DECFJABLMIGHK深度优先生成森林DEGHKCFIJABLMG3

第55页:最小生成树问题

(2)最小生成树

  • 问题引出:以n-1条边连接n个顶点并使代价最小
  • 方法有:
  • 普里姆(Prim)算法
  • 克鲁斯卡尔(Kruskal)算法返回

第56页:普里姆算法思想

1)普里姆算法

  • 算法思想:
  • 设N=(V,{E})是连通网,TE是N上最小生成树中边的集合
  • 初始令U={u0},(u0V),TE=
  • 在所有uU,vV-U的边(u,v)E中,找一条代价最小的边(u0,v0)
  • 将(u0,v0)并入集合TE,同时v0并入U
  • 重复上述操作直至U=V为止,则T=(V,{TE})为N的最小生成树
  • 算法实现:图用邻接矩阵表示
  • 算法评价:T(n)=O(n²)

第57页:普里姆算法举例

1654326513566425131163141643142116432142516543214253普里姆算法举例

第58页:普里姆算法实现

普里姆算法

  • //用普里姆算法从第u个顶点出发构造网G的最小生成树T,输出T的各条边
  • voidMiniSpanTree_PRIM(MgraphG,VertexTypeu){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;for(i=1;i<G.vexnum;++i){//初始,U={u}//选择其余G.vexnum-1个顶点k=minimum(closedge);//求出T的下一个结点:第k顶点//此时clodedge[k].lowcost=//MIN{closedge[vi].lowcost∣closedge[vi].lowcost>0,vi∈V-U}

第59页:普里姆算法续:重新选最小边

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}}//for}//for

  • }//MiniSpanTree
  • //时间复杂度为O(n2)

第60页:普里姆算法应用程序

普里姆算法构造最小生成树应用程序mx[1][2]=50;mx[1][3]=60;mx[2][4]=65;mx[2][5]=40;mx[3][4]=52;mx[3][7]=45;mx[4][5]=50;mx[5][6]=70;mx[4][6]=30;mx[4][7]=42;

第61页:克鲁斯卡尔算法

2)克鲁斯卡尔(Kruskal)算法

  • 思路:它以边为搜索对象,时间复杂度为O(eloge),因而适合稀疏矩阵情况
  • 步骤:
  • 先构成只有n个顶点而无边的非连通图T=(V,{});
  • 在边集E中选择代价最小的边e;
  • 若该边所依附的顶点落在T中不同的连通分量上,将此边加入到T中,否则选择下一条代价最小的边
  • 依此类推,直到T中所有顶点都落在同一连通分量上为止返回

第62页:第五节有向无环图及其应用

第五节有向无环图及其应用

第63页:有向无环图的概念

有向无环图(directedacyclinegraph,DAG):一个无环的有向图

  • 应用:
  • 描述具有公共子式的表达式,节省存储空间(图7.22、7.23)
  • 描述一个工程或系统进行过程的有效工具返回

第64页:工程与子工程的关系

例如:

  • 一个工程若干个子工程组成,而某些子工程开始必须在另一些工程完成之后才能进行
  • 对于整个工作关心两件事:
  • 工程能否顺利进行?O估算整个工程完成所必须的最短时间?
  • 操作:
  • 拓扑排序
  • 关键路径

第65页:拓扑排序的概念

(1)拓扑排序

  • 概念:
  • 偏序:集合中只有部分成员可以比较
  • 全序:集合中全体成员可以比较
  • 拓扑排序:由某个集合上的一个偏序得到该集合上的一个全序
  • 一个表示偏序的有向图可以用来表示流程图:施工或生产过程、某专业的课程安排顺序

第66页:AOV-网

AOV-网概念:用顶点表示活动、边表示两个活动间的次序关系的有向图称为顶点表示活动的网(ActivityOnVertexNetwork)

  • AOV-网中,不应该出现有向环;检测方法是对有向图构造其顶点的拓扑有序序列,若网中所有顶点都在它的拓扑有序序列中,则该AOV-网不存在环

第67页:拓扑排序的过程

1)拓扑排序过程

  • 在有向图中选一个没有前驱的的顶点且输出
  • 在图中删除该顶点和所有以它为尾的弧
  • 重复上述两步,直到全部顶点均已输出
  • 注意:同一有向无环图可以构造不同的拓扑有序序列
  • 当有向图无环时,可以利用深度优先遍历进行排序

第68页:拓扑排序举例

举例先修棵课程名称课程代号无程序设计基础C1C1离散数学C2C1,C2数据结构C3C1汇编语言C4C3,C4语言的设计和分析C5C11计算机原理C6C3.C5编译原理C7C3,C6操作系统C8无高等数学C9C9线性代数C10C9普通物理C11C1,C9,C10数值分析C12C1C3C4C2C5C6C7C8C9C10C11C12

第69页:拓扑序列不唯一

C1C2C3C4C5C6C7C8C9C10C12C11拓扑序列:C1--C2--C3--C4--C5--C7--C9--C10--C11--C6--C12--C8或:C9--C10--C11--C6--C1--C12--C4--C2--C3--C5--C7--C8一个AOV网的拓扑序列不是唯一的

第70页:AOV网顶点图

C1C2C3C4C5C6C7C8C9C10C11C12

第71页:拓扑排序步骤(一)

C2C3C4C5C6C7C8C9C10C11C12拓扑序列:C1(1)C3C4C5C6C7C8C9C10C12C11拓扑序列:C1--C2(2)

第72页:拓扑排序步骤(二)

C4C5C6C7C8C9C10C11C12C5C6C7C8C9C10C11C12拓扑序列:C1--C2--C3(3)拓扑序列:C1--C2--C3--C4(4)

第73页:拓扑排序步骤(三)

C6C8C10C11拓扑序列:C1--C2--C3--C4--C5--C7--C9C6C11拓扑序列:C1--C2--C3--C4--C5--C7--C9--C10(8)拓扑序列:C1--C2--C3--C4--C5(5)C12C6C7C8C9C10C11C12C6C8C9C10C12C11拓扑序列:C1--C2--C3--C4--C5--C7(6)C12C8

第74页:拓扑排序步骤(四)

C6C8C12(9)C8C12(10)拓扑序列:C1--C2--C3--C4--C5--C7--C9拓扑序列:C1--C2--C3--C4--C5--C7--C9--C10--C11--C10--C11--C6C8拓扑序列:C1--C2--C3--C4--C5--C7--C9--C10--C11--C6--C12(11)拓扑序列:C1--C2--C3--C4--C5--C7--C9--C10--C11--C6--C12--C8(12)

第75页:拓扑排序算法

2)拓扑排序算法

  • //有向图G采用邻接表存储结构
  • //若G无回路,则输出G的顶点的一个拓扑序列并返回OK,否则ERROR
  • //为了避免重复检测入度为零的点,设置一个栈暂时存放所有入度为零的顶点
  • StatusTopologicalSort(AlGraphG){FindinDegree(G,indegree);indegree[0..vernum-1]InitStack(s);for(i=0;i<G.vexnum;++i)if(!indegree[i])push(s,i);Count=0;//对各顶点求入度//建零入度顶点栈s//入度为0者进栈//对输出顶点计数

第76页:拓扑排序算法续

While(!StackEmpty(S)){ Pop(s,i); printf(i,G.vertices[i].data); ++count;p; p=p->nextarc){ k=p->adjvex;//若入度减为0,则入栈}//whileif(count<G.vexnum)returnERROR;} 

第77页:关键路径与AOE网

(2)关键路径

  • AOE-网:
  • 以边表示活动的网,是一个带权的有向无环网;
  • 顶点表示事件、边表示活动
  • 网中只有一个入度为零的点和一个出度为零的点
  • 研究问题:
  • 完成整个工程至少需要多少时间?
  • 哪些活动是影响工程进度的关键?
  • 关键路径:
  • 完成一个工程的最短时间是从开始点到完成点的最长路径的长度(活动持续时间的长度,并非路径上的弧段数)
  • 路径长度最长的路径叫关键路径

第78页:事件的最早与最迟发生时间

开始点v1到vj的最长路径长度叫事件vj的最早发生时间Ve(j)

  • 事件vj的允许最迟发生时间Vl(j)是在保证汇点vn在e(n)时刻发生的前提下事件允许发生的最晚时间,它等于Ve(n)减去vj到vn的最长路径长度
  • 设活动ai(<vj,vk>)的最早开始时间为e(i)、最迟开始时间为l(i),l(i)-e(i)为活动ai的最大可利用时间,如果l(i)=e(i),则表明ai是关键活动,必须在e(i)时间开始立即执行才不会影响工程进度
  • 其中:e(i)=Ve(j)<事件vj的最早发生时间ve(j)>l(i) =Vl(k)-dut<j,k>Ve(j)Vl(k)v1aijkvn

第79页:关键路径举例

例如:

  • v1到v9的的最长路径长度是18(v1,v2,v5,v8,v9)
  • 事件v9的最早发生时间是18
  • 活动a6的最早开始时间是5,最迟开始时间是8(18-a11-a9-a6)意味着活动a6推迟3天开始不会影响整个工程
  • 求关键路径就是判断那些是关键活动,以便在关键活动上提高它的功效,从而缩短整个工期
  • 关键活动就是e(i) =l(i)的活动987465321a2=4a3=5a5=1a6=2a9=4a1=6a4=1a7=9a8=7a10=2a11=4AOE-网

第80页:关键路径算法过程

1)关键路径算法过程

  • 输入e条弧,建立AOE网
  • 从源点v0出发,令ve[0]=0,按拓扑有序求其余各点的最早发生时间Ve[i]
  • 从汇点vn出发,令vl[n-1]=ve[n-1],按拓扑逆序求其余各点的最迟发生时间Vl[i]
  • 根据各顶点的Ve和Vl值,求各(活动)弧的最早开始时间e和最迟开始时间l
  • 若某条弧ak满足e(k) =l(k),则为关键活动
  • 从图中删除非关键活动,有所有关键活动组成的从源点到汇点的路径为关键路径

第81页:关键路径求解步骤表

求关键路径步骤

  • 求Ve(i)
  • 求Vl(j)
  • 求e(i)< =Ve(j) >
  • 求l(i)<=Vl(k)-dut<j,k>>
  • 计算l(i)-e(i)l-ele活动0
  • 00a1220a2330a30
  • 66>a4264a5385a60
  • 77a70
  • 77a83107a90
  • 1616a100
  • 1414a11VlVe顶点00V1Vl66V264V385V477V5107V61616V71414V818V918987645321a2=4a3=5a5=1a6=2a9=4a1=6a4=1a7=9a8=7a10=2a11=4(5)-dut<j,k

第82页:关键路径实例

朋根东华理工学院程2)实例

第83页:拓扑排序求Ve算法

3)关键路径算法

  • StatusTopologicalOrder(ALGraphG,Stck&T){//有向网G采用邻接表(+逆邻接表)存储结构,求各顶点的最早发生时间ve(全局变量)//T为拓扑序列顶点栈,S为零入度顶点栈。//若G无回路,则用栈T返回G的一个拓扑序列,且函数值为Ok,否则为ERROR。FindinDegree(G,indregee);//对各顶点求入度indegree[0..vernum-1]InitStack(S);

    第84页:拓扑排序求Ve算法续

    东华理工学院程朋根While(!StackEmpty(S)){ Pop(S,j); push(T,j); ++count;p; p=p->nextoutarc){ k=p->adjvex;//若入度数为0,则入栈if(ve[j]+*(p->info)>ve[k])ve[k]=ve[j]+*(p->info);//for*(p->info)=dut(<j,k>)}//该有向网有回路if(count<G.vexnum)elsereturnOk; } 

    第85页:关键路径算法CriticalPath

    StatusCriticalPath(ALGraphG){Vl[0…G.vexnum-1]=Ve[0..G.vexnum-1];>nextinarc){ k=p->adjvex; dut=*(p->info);p; p=p-if(vl[j]-dut <Vl[k])Vl[k]=Vl[j]-dut; } 

    第86页:关键活动输出

    for(j=0; j<G.vexnum; ++j)//求ee,el和关键活动for(p=G.vertices[j]; p; p=p->nextoutarc){ k=p->adjvex; dut=*(p->info); ee=Ve[j]; el=Vl[k]-dut; tag=(ee==el)?‘*’:‘’; printf(j,k,dut,ee,el,tag);} 

    第87页:第六节最短路经

    第六节最短路经

    第88页:最短路径问题

    最短路径问题

    • 在交通图上求中转次数最少的路径(边数最少),采用广度优先搜索
    • 交通费、时间、里程等
    • 术语
    • 源点(Sourse):路径上的第一个顶点
    • 终点(Destination):路径上的第后一个顶点
    • 从某个源点到其余各点的最短路径
    • 每一对顶点之间的最短路径

    第89页:单源最短路径

    (1)从某个源点到其余各点的最短路径

    • 举例北京到各大省城最短路径物流运输中某货源地到各需求点的最短路径
    • 方法
    • 迪杰斯特拉(Dijkstra)

    第90页:迪杰斯特拉算法步骤

    1)迪杰斯特拉(Dijkstra)算法步骤

    • (1)求从v点到其余各点vi最短路径长度的初值
    • D[i]=arcs[LocateVex(G,v)[i]]|viV
    • S赋空,如P190表的第一列,
    • (2)选择vj,使得D[j]=Min{D[i]|viV-S},vj为当前求得的一条从v出发的最短路径终点,S=SU{j},如二行一列的10,(v0,v2)
    • (3)修改从v出发到集合V-S上任意一点vk可达到的最短路径长度
    • 如果D[j]+arcs[j][k]<D[k],则D[k]=D[j]+arcs[j][k]
    • 例如三行一列的无穷大改为60
    • (4)重复(2),(3)共n-1次,即可求得v到各点的最短路径

    第91页:迪杰斯特拉求解过程表

    从V0到各终点的D值和最短路径求解过程终点I=5I=4I=3I=2I=1∞无∞∞∞∞V110(V0,V2)V250(V0,V4,V3)60(V0,V2,V3)∞V330(V0,V4)30(V0,V4)V460(V0,V4,V3,V5)90(V0,V4,V5)100(V0,V5)100(V0,V5)V5V5V3V4V2Vj{V0,V2,V3,V4,V5}{V0,V2,V4,V3}{V0,V2,V4}{V0,V2}S2)实例

    第92页:迪杰斯特拉算法实现

    3)迪杰斯特拉(Dijkstra)算法

    • voidShortestpath_DIJ(MgraphG,intv0,PathMatrix&p,shortPathTable&D){//用Dijkstra算法求有向网G的v0顶点到其余顶点v的最短路径p[v]及其带权长度D[v]//若p[v][w]为TRUE,则w是从v0到v当前求的最短路径上的顶点//final[v]为TRUE当且仅当v∈s,即已经求得从v0到v的最短路径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(D[v]<INFINITY){p[v][v0]=TRUE;p[v][v]=TRUE;}}//forD[v0]=0;final[v0]=TRUE;//初始化,v0顶点属于S集

    第93页:迪杰斯特拉算法续

    2)迪杰斯特拉(Dijkstra)算法(续)//开始主循环,每次求得v0到某个v顶点的最短路径,并加v到s集for(i=1;i<G.vexnum;++i){min=INFINITY;//其余G.vexnum-1个顶点//当前所知离v0顶点的最近距离for(w=0;w<G.vexnum;++w)if(!final[w])//w顶点在v-s中if(D[w]<min){v=w;min=D[w];}//w顶点离v0顶点更近final[v]=TRUE;for(w=0;w<G.vexnum;++w)//离v0顶点最近的v加入s集//更新当前最短路径及距离if(!final[w]&&(min+G.arcs[v][w]<D[w])){//修改D[w]和p[w],w∈v-sD[w]=min+G.arcs[v][w];p[w]=p[v];}//if}//forp[w][w]=TRUE;// p[w] =p[v]+[w],行相加

    • }//shortestPath_DIJ,时间复杂度为O(n2)

    第94页:Dijkstra算法应用程序

    Dijkstra算法求最短路径应用程序cost[1][2]=50;cost[1][3]=10;cost[1][5]=45;cost[2][3]=15;cost[2][4]=50;cost[2][5]=10;cost[3][1]=20;cost[3][4]=15;cost[4][2]=20;cost[4][5]=35;cost[5][4]=30;cost[6][4]=3;

    第95页:每对顶点之间的最短路径

    (2)每一对顶点之间的最短路径

    • 每次以一个顶点为源,重复执行迪杰斯特拉算法时间复杂度为O(n3)
    • 弗洛伊德(Floyd)法求Vi到Vj的最短路径:
    • 如果从Vi到Vj存在弧,则arcs[i][j]是从Vi到Vj的路径,但不是最短路径,需要进行n次测试
    • 首先考虑(Vi,V0,Vj)是否存在,如果存在则在(Vi,Vj)和(Vi,V0,Vj)之间中取长度最短的路径为从Vi到Vj的中间顶点不大于0的路径
    • 依次类推。

    第96页:弗洛伊德算法的思路

    ViVjVkk =0,1,2,…,k

    • 若(Vi,…,Vk)和(Vk,…Vj)分别为是从Vi到Vk和从Vk到Vj的中间顶点号不大于k-1的最短路径,则将(Vi,…,Vk,…Vj)和已得到的从Vi到Vj且中间顶点序号不大于k-1的最短路径比较,长度最短者便是从Vi到Vj的中间顶点序号不大于k的最短路径
    • 经过n次比较后,并可求得从Vi到Vj的最短路径点号k值为0,1,2,…,k-1

    第97页:弗洛伊德算法实现

    1)弗洛伊德(Floyd)算法

    • //用Floyd算法求有向网G中各对顶点v和w之间的最短路径p[v][w]及其带权长度D[v][w]。若p[v][w][u]为TRUE,则u是从v到w当前求得最短路径上的顶点。
    • VoidShortestpath_FLOYD(MGRaph,pathMatrix&p[],DistancMatrix&D){for(v=0;v<G.vexnum;++v)//各对结点之间初始已知路径及距离for(w=0;w<G.vexnum;++w){D[v][w]=G.arcs[v][w];for(u=0;u<G.vexnum;++u)p[v][w][u]=FALSE;if(D[v][w]<INFINITY){//从v到w有直接路径P[v][w][v]=TRUE;p[v][w][w]=TRUE;}//if}//for

    第98页:弗洛伊德算法续

    for(u=0;u<G.vexnum;++u)for(v=0;v<G.vexnum;++v)for(w=0;w<G.vexnum;++w)if(D[v][u]+D[u][w]<D[v][w])经u到w的一条路径更短D[v][w]=D[v][u]+D[u][w];for(i=0;i<G.vexnum;++i){//从vp[v][w][i]=p[v][u][i]‖p[u][w][i];}//if

    • }//ShortestPath_FLOYD

    第99页:弗洛伊德算法实例

    AB236411C0411初始:60230ACABBC:BACA路径046加入V2:602370BABCABBC:BACABCA路径0411加入V1:602370AACABBC:BACABCA路径046加入V3:502370C路径:ABCABBCBCACABCA算法分析:T(n)=O(n³)2)实例

    第100页:本章重点

    本章重点

    • 图的定义、术语和存储结构
    • 图的遍历
    • 最小生成树
    • 关键路径
    • 最短路经

    第101页:习题(一)

    习题:

    • 1、在一个图中,所有顶点的度数之和等于所有边数的2倍;而在一个有向图中,所有顶点的入度数之和等于所有顶点的出度数之和的1倍。
    • 2、具有4个顶点的无向完全图有6条边。
    • 3、对于一个具有n个顶点的无向图,若采用邻接矩阵表示,则该矩阵的大小是n2。
    • 4、对于对于一个具有n个顶点和e条边的无向图,若采用邻接表表示,则表头向量的大小为n,所有邻接表中的结点总数为2e;若采用邻接多重表表示,则表头向量的大小为n,所有邻接多重表中的结点总数为e。

    第102页:习题(二)

    5、采用邻接表存储图的深度优先遍历法算类似与二叉树的先序遍历,而广度优先遍历算法类似与二叉树的层序遍历。

    • 6、已知一个有向图用邻接矩阵表示,则计算第i结点入度的方法是求矩阵第i列非0元素之和。
    • 7、图的深度优先搜索序列和广度优先搜索序列是不惟一的。
    • 8、对于稠密图和稀疏图,采用邻接矩阵和邻接表哪个更好?

    第103页:习题(三)

    9、注意阐述题类型:

    • 根据一个图或图的邻接表表示存储结构,写出图的深度优先和广度优先搜索的顶点系列。(课堂作业)
    • 根据图和和边的权值,描述采用谱里姆算法生成最小生成树的过程。(P174的图、表)
    • 根据一个有向图,求原点到其它各点最短路径.(用表描述,见图7.34和P190表格)