1、,3.6.1 图的基本概念 3.6.2 图的存储 3.6.3 图的遍历 3.6.4 图的应用,3.6 图,3.6.1 图的基本概念,B,A,C,D,6,3,2,1,5,数据结构 B=(D,R) 图: G=(V,E) 顶点:图中的数据元素,V:表示顶点的非空有限集合。 E:表示两个顶点之间关系的集合。,图的定义、术语,图,有向图,无向图,在有向图中,表示从V1到V3的一条弧。V1为弧尾或初始点,V3为弧头或终端点。,在无向图中,(V1,V3)表示V1和V3之间的一条边。,V1,V3,V2,V4,图的定义、术语,V1,V3,V2,V4,顶点集合V=V1 , V2 , V3 , V4 ,弧的集合G=
2、, , , ,顶点集合V=V1 , V2 , V3 , V4 ,边的集合E=(V1, V3), (V1, V2),(V1, V4),(V2, V4),G=( V, E ),顶点(V1, V3)与 (V3, V1)表示同一条边,图的定义、术语,B,A,C,D,6,3,2,1,5,权:与图的边或弧相关的数。,顶点的度:依附于该顶点的边数或弧数。,出度:(仅对有向图)以该顶点为尾的弧数。,入度:(仅对有向图)以该顶点为头的弧数。,路径:顶点A与顶点C之间存在一条路径。路径上边或弧的数目称为该路径的路径长度。 连通图:无向图任意两顶点都有路径(没有孤立顶点) 强连通图:有向图任意两顶点都有路径 网:带
3、权的图称为网,图的定义、术语,图的存储 邻接矩阵,3.6.2 图的存储 1. 邻接矩阵法 (1)给顶点编号 (2)建立邻接(关系)矩阵,1 2 3 4,1 2 3 4,0 0 0 0,1 0 1 1,1 0 0 1,0 1 1 0,a i j表示弧 1:表示有弧;0:表示无弧,任意顶点的出度是该行元素之和 任意顶点的入度是该列元素之和,图的存储 邻接矩阵,邻接矩阵的优点: 增减边的操作简单 邻接矩阵的缺点: 增减顶点的操作需要搬移大量的元素, 浪费存储空间,1 2 3 4,1 2 3 4,0 1 1 0,1 0 1 1,1 1 0 1,0 1 1 0,无向图的邻接矩阵是对称的,图的存储 邻接矩
4、阵的实现,图的邻接矩阵实现,typedef struct graph_melemtype nodeMAXNUM;int arcsMAXNUMMAXNUM; graph_m;,顶点集合,边的邻接矩阵,二维数组,图的存储 邻接表,2. 邻接表法一个邻接表由两种结构组成 存放各顶点元素的数组,头结点 各顶点各自的邻接链表,邻接结点,3,data,顶点号,元素域,邻接链表头指针,邻接顶点号,下一邻接结点,图的存储(课堂练习),请写出下面这副图的邻接表 1)给顶点编号 2)建立顶点数组 3)建立各顶点的邻接链表 注意,此图为有向图,2,1,3,4,5,图的存储 邻接表的实现,邻接表的定义 头结点的定义邻
5、接结点的定义,typedef struct headnodeint node_index;elemtype data;struct adj_node * next_adj; headnode;,typedef struct adj_nodeint node_index;struct adj_node *next_adj; adj_node;,图的存储 邻接表,图邻接表的定义,typedef struct graph_lheadnode node_listMAXNUM;int node_num; graph_l;,图的存储 邻接表,2,1,4,3,2,1,4,3,注意:有向图与无向图的区别,图的
6、存储,图的邻接表存储法的特点 优点 节省存储空间 边的插入和删除操作比较简便 缺点 结构复杂 具有两种不同的基本组成单元,图的存储,3. 边带权值的图的存储 1)在邻接矩阵中的实现,0 2 3 5 0 1 0 1 0 1 5 0 1 0,a44 =,a i j :记录边的权值;为0表示无边,2,3,5,1,1,图的存储,3. 边带权值的图的存储 2)在邻接表中的实现 在邻接结点结构中增加一个权值域,顶点号,边权值,1,2,4,3,3,2,5,1,1,10,3,图的遍历,3.6.3 图的遍历 问题: 1)对于连通图,从一个顶点出发沿着所有可能的路径,是否可以将所有的顶点遍历到。 2)图中有回路,
7、遍历算法可能产生死循环。 有重复的路径称为回路,图的遍历 深优,1. 深度优先遍历 (1)从一个未访问过的顶点开始,访问它的一个未访问过的相邻顶点。 (2)如果顶点的所有相邻顶点都是已访问过的,则需要回溯到之前的一个顶点,选取它的另一个未被访问的相邻顶点。 (3)对于前两个步骤是递归的,图的遍历 深优,1. 深度优先遍历 (1)从一个未访问过的顶点开始,访问它的一个未访问过的相邻顶点。 (2)如果顶点的所有相邻顶点都是已访问过的,则需要回溯到之前的一个顶点,选取它的另一个未被访问的相邻顶点。 (3)对于前两个步骤是递归的,1,2,5,8,4,6,3,7,1,7,3,6,5,2,8,4,1,7,
8、3,6,5,2,8,4,1 3 6 8 4 2 5 7,或者按以下顺序遍历:,注意使用栈支持递归:,图的遍历 深优,深度优先遍历的特点 “深度”:总是访问顶点的一个相邻顶点,好像是沿着图中的一条路径走到“底”,然后后退一点,再选一条路。如此“进进退退”,直到所有顶点都被访问 对于连通图,如果第一个被访问的顶点的所有相邻顶点都被访问了,意味着图中所有顶点都被访问了。 即栈空时,图的遍历 深优,用递归调用实现深度优先遍历算法,void dfs (g,v),1访问顶点v;,visit(v);visited v = 1;,p = gv-next_adj while(p != NULL)w = p-no
9、de_index;if(visitedw = 0)p = p-next_adj; ,2取得顶点的一个未被访问过的顶点w;,3 dfs(g,w);回到2;,4重复2,3直到该顶点所有的相邻顶点都被访问过;,dfs(g,w);,void dfs(g ,v)visited v = 1;p = g v -next_adjwhile(p != NULL)w = p-node_index;if(visited w = 0)dfs( g, w );p = p-next_adj;,void dfs(g ,2)visited 2 = 1;p = g 2 -next_adjwhile(p != NULL)w =
10、p-node_index;if(visited 3 = 0)dfs( g, 3 );p = p-next_adj; ,void dfs(g ,3)visited 3 = 1;p = g 3 -next_adjwhile(p != NULL)w = p-node_index;if(visited 4 = 0)dfs( g , 4 );p = p-next_adj; ,void dfs(g ,4)visited 4 = 1;p = g 4 -next_adjwhile(p != NULL)w = p-node_index;if(visited w = 0)dfs( g , w );p = p-ne
11、xt_adj; ,void dfs(g ,5)visited 5 = 1;p = g 5 -next_adjwhile(p != NULL)w = p-node_index;if(visited w = 0)dfs( g , w );p = p-next_adj;,void dfs(g ,1)visited 1 = 1;p = g 1 -next_adjwhile(p != NULL)w = p-node_index;if(visited 2 = 0)dfs( g, 2 );p = p-next_adj; ,if(visited 5 = 0),dfs( g , 5 );,图的遍历 广优,2.
12、广度优先遍历 访问顶点v后,接着依次访问v的所有邻接顶点,再依次访问这些邻接顶点的邻接顶点。直到所有的顶点都被访问过。,1,2,5,8,4,6,3,7,1,2,3,4,5,6,7,8,注意:8是作为哪个顶点的邻接顶点被访问的?,1,2,3,4,5,6,7,8,体会队列操作方式:,图的遍历 广优,广度优先遍历的特点 “广度”:总是在访问了一个顶点后,依次访问它的所有相邻顶点。然后再从它的第一个相邻顶点开始,访问其所有的相邻顶点。如此逐个顶点地逐步扩散,直到所有的顶点都被访问。 广度优先遍历操作具有队列操作的特点,当从队列中取出最后一个顶点,发现该顶点的所有相邻顶点都被访问过时,意味着图中所有的顶
13、点都已被访问过,生成树与图,3.6.4 图的应用 1. 生成树定义 假设存在这样一颗树: 树结点的集合与图的顶点集合相等 树的分支全部由图的边组成。称这颗树是这幅图的生成树 生成树是图的: 子集/子图 是一个不包含回路的子图 图的生成树是,2,1,4,3,不唯一的!,唯一的!,取决于遍历方法和遍历的起始点,生成树的示例,生成树与图,对于一个有n个顶点的连通图G, 其生成树包含了 条边。,深度优先搜索得到的生成树,广度优先搜索得到的生成树,n1,权值,生成树与图,2. 最小费用生成树(通信网络、交通网络) 在图所有生成树中,边的权值总和最小的生成树,6,5,3,6,6,4,2,4,1,6,边,1
14、3,1,46,2,25,3,14,4,36,4,23,5,12,6,35,6,56,6,将边按权值大小排列,生成树与图,算法分析关键技术: 为什么在(1,4)边选中后不能选(3,6)边 在选择(3,6)边和(2,3)边时有什么不同,怎样设置条件以区别? 当时3和6位于同一图中,2、5和3位于不同的图中,6,5,3,6,6,4,2,4,1,6,14,4,36,4,23,5,回路,生成树与图,1)开始时所有的节点都位于不同的图中,2)选择一条连接两个不同子图的最短边,3)连接以后两个子图的所有顶点都要改为在一个子图中,4)当所有的顶点都位于一个子图中,算法结束。,权值,边,13,1,46,2,25
15、,3,14,4,36,4,23,5,12,6,思考,既然是颗树,如果选择边数为n1个时可不可以结束算法呢? 算法的优化,图的最短路径,3 .最短路径 图中两个顶点之间有 条路径 最短路径: 是路径中边(弧)的权值总和最小的路径 计算机网络中常使用最短路径算法计算最佳路径 交通网络中使用最短路径算法计算最短旅途,多,Dijkstra Algorithm,Floyd Algorithm,A1,A2,A4,A3,A5,2,6,5,1,2,1,5,1)初始化时,设A1到其它不直连顶点距离为,寻找A1到所有节点的最短路径,A2,A3,A4,A5,顶点,距离,路径,2)选择距离最短的路径,3)观察通过新选
16、择的路径是否能更短地到达其它顶点,4)选择出的最短路径将不参加下一轮比较,5)反复2 - 4步,直到不剩有顶点,2,6,5,A2,A3,A4,A1 A2 A33,更新,A1 A2 A3,3,A1 A2 A4 ,A1 A2 A5 4,A1 A2 A3 A44,更新,A1 A2 A3 A4,4,A1 A2 A3 A58,A1 A2 A5,4,A1 A2 A3 A4 A5,更新,Dijkstra Algorithm,拓 扑 排 序,按一定顺序进行的活动,可以使用顶点表示活动、顶点之间的有向边表示活动间的先后关系的有向图来表示,这种有向图称为顶点表示活动网络(Activity On Vertex ne
17、twork,简称AOV网)。 AOV网中的有向边表示了活动之间的制约关系。,4. 拓 扑 排 序,将AOV网中的所有顶点排列成一个线性序列vi1, vi2, , vin,并且这个序列同时满足关系:若在AOV网中从顶点vi到顶点vj存在一条路径,则在线性序列中vi必在vj之前,我们就称这个线性序列为拓扑序列。把对AOV网构造拓扑序列的操作称为拓扑排序。 在实际的意义上,AOV网中存在的有向环就意味着某些活动是以自己为先决条件,这显然是荒谬的。例如对于程序的数据流图而言,AOV网中存在环就意味着程序存在一个死循环。,任何一个无环的AOV网中的所有顶点都可排列在一个拓扑序列里,拓扑排序的基本操作如下
18、:(1) 从网中选择一个入度为0的顶点并且输出它。(2) 从网中删除此顶点及所有由它发出的边。(3) 重复上述两步,直到网中再没有入度为0的顶点为止。,以上的操作会产生两种结果: 一种是网中的全部顶点都被输出,整个拓扑排序完成; 另一种是网中顶点未被全部输出,剩余的顶点的入度均不为0,则说明网中存在有向环。 用以上操得到了一种拓扑序列: C1, C2 , C3, C4, C5, C7, C9, C10, C12, C11, C6, C8。 拓扑序列可以是 种,多,AOV网拓扑排序过程,在邻接表存储结构中实现拓扑排序算法的步骤为:(1) 扫描顶点表,将入度为0的顶点入栈。(2) 当栈非空时执行以
19、下操作: 将栈顶顶点vi的序号弹出,并输出之;检查vi的出边表,将每条出边表邻接点域所对应的顶点的入度域值减1,若该顶点入度为0,则将其入栈;(3) 若输出的顶点数小于n,则输出“有回路”,否则拓扑排序正常结束。,关 键 路 径,5. 关键路径 AOE网络(Activity On Edge network): 有向边:表示一个子工程(活动) 边上的权值:表示一个活动持续的时间 顶点:表示事件,它表示了一种状态,即它的入边所表示的活动均已完成,它的出边所表示的活动可以开始。 这种带权的有向网络称为 AOE网络(Activity On Edge network),即边表示活动网络。,一个AOE网络
20、的示例,关键路径:从源点到汇点的具有最大路径长度的路径。 关键活动:关键路径上的各个活动。 明确了哪些活动是关键活动就可以设法提高关键活动的功效,以便缩短整个工期。,其中E1是网络中以vj为终点的入边集合,dur()是有向边 上的权值。 vl(j)的计算可从汇点开始,向源点逆推计算:(13.2)其中E2是网络中以vj为起点的出边集合。,(1),(2),ve(j)的计算可从源点开始利用以下的递推公式求得,ve(1)=0 ve(2)=maxve(1)+dur()=max0+3=3 ve(3)=maxve(1)+dur()=max0+2=2 ve(4)=mawve(2)+dur(), ve(3)+d
21、ur()=max3+4, 2+3=7 ve(5)=maxve(4)+dur(), ve(2)+dur()=max7+4, 3+8=11 ve(6)=maxve(3)+dur(), ve(4)+dur()=max2+7, 7+2=9 ve(7)=maxve(5)+dur(), ve(6)+dur()=max11+9, 9+6=20 vl(7)=ve(7)=20,按(1)式和(2)式,可计算出图该AOE网各个事件的最早发生时间和最迟发生时间:,vl(6)=minvl(7)dur()=min206=14 vl(5)=minvl(7)dur()=min209=11 vl(4)=minvl(5)dur(
22、), vl(6)dur()=min114, 112=7 vl(3)=minvl(4)dur(), vl(6)dur()=min73, 147=4 vl(2)=minvl(4)dur(), vl(5)dur()=min74, 118=3 vl(1)=minvl(2)dur(), vl(3)dur()=min33, 42=0,利用 ve(i)=e(i) 和l(i)=vl(k)dur(),网络的关键路径,关键活动算法主要由以下步骤组成:(1) 对AOE网进行拓扑排序,同时按拓扑排序顺序求出各顶点事件的最早发生时间ve,若网中有回路,则算法终止,否则执行(2)。(2) 按拓扑序列的逆序求出各顶点事件的最迟发生时间vl。 (3) 根据ve和vl的值求出ai的最早开始时间e(i)和最迟开始时间l(i)。若l(i)=e(i),则ai为关键活动。因为计算各顶点的ve值是在拓扑排序的过程中进行的,所以可通过对拓扑排序算法进行一些修正来实现求关键路径的算法。,作业,一个网络及其邻接矩阵,Kruskal算法构造最小生成树的过程,