1 / 63

6 图 (1)

6 图 (1). 教学目标. 熟练掌握图的概念和术语,图的邻接矩阵与邻接表两种存储方法。 熟练掌握图的遍历的概念,图的 DFS 与 BFS 方法与算法。 掌握最小生成树的概念,构造最小生成树的方法,求图的最小生成树的算法。 掌握最短路径的概念,图的单源点最短路径的求解方法。了解单源点最短路径的算法; 掌握拓扑排序和关键路径的方法 , 了解拓扑排序和关键路径的算法。. 教学内容. 6.1 图的定义和术语 6.2 图的存储表示 6.3 图的遍历 6.4 最小生成树 6.5 两点之间的最短路径问题 6.6 拓扑排序 6.7 关键路径. 问题回顾.

brina
Download Presentation

6 图 (1)

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. 6 图(1)

  2. 教学目标 熟练掌握图的概念和术语,图的邻接矩阵与邻接表两种存储方法。 熟练掌握图的遍历的概念,图的DFS与BFS方法与算法。 掌握最小生成树的概念,构造最小生成树的方法,求图的最小生成树的算法。 掌握最短路径的概念,图的单源点最短路径的求解方法。了解单源点最短路径的算法; 掌握拓扑排序和关键路径的方法,了解拓扑排序和关键路径的算法。

  3. 教学内容 6.1 图的定义和术语 6.2 图的存储表示 6.3 图的遍历 6.4 最小生成树 6.5 两点之间的最短路径问题 6.6 拓扑排序 6.7 关键路径

  4. 问题回顾

  5. 6.1 图的定义和术语 图的定义:图是由一个顶点集 V 和一个边集 E构成的数据结构。 G = (V , E ) 其中:G表示一个图,V是图G中顶点的集合,E是图G中顶点之间边的集合。 若顶点v和w之间的边没有方向,则称这条边为无向边,表示为(v, w)。相应的图称为无向图。 若从顶点v到w的边有方向,则称这条边为有向边(又称为弧),表示为<v, w>。相应的图称为有向图。

  6. 例如:G1 = (V1, E1) 是有向图 其中 V1={A, B, C, D, E} E1={<A,B>, <A,E>, <B,C>, <C,D>, <D,B>, <D,A>, <E,C> } A B E C D B C A D F E 例如: G2=(V2,E2) 为无向图 V2={A, B, C, D, E, F} E2={(A,B), (A,E),(B,E), (C,D), (D,F),(B,F), (C,F) }

  7. 名词和术语 网、子图 完全图、稀疏图、稠密图 邻接点、度、入度、出度 路径、路径长度、简单路径、简单回路 连通图、连通分量、 强连通图、强连通分量 生成树、生成森林

  8. A 9 15 带权的图分别称作有向网或无向网。 11 B E 7 21 3 C F 2 B 设图G=(V,E) 和图G=(V,E), 且VV, EE, 则称G 为 G 的子图。 A B E C F

  9. 假设图中有 n个顶点,e条边,则 含有 e=n(n-1)/2 条边的无向图称作完全图; 含有 e=n(n-1)条弧的有向图称作 有向完全图; 若边或弧的个数 e < nlogn,则称作稀疏图,否则称作稠密图。

  10. 对无向图来说, 假若顶点v 和顶点w 之间存在一条边, 则称顶点v和w互为邻接点, 边(v,w)和顶点v 和w相关联。 和顶点v 关联的边的数目定义为顶点的度。 B C 例如: D TD(B) = 3 A TD(A) = 2 E F

  11. 对有向图来说, A 顶点的出度: 以顶点v为弧尾的弧的数目; B E C D 顶点的入度: 以顶点v为弧头的弧的数目。 例如: OD(B) = 1 顶点的度(TD)= 出度(OD)+入度(ID) ID(B) = 2 TD(B) = 3

  12. 设图G=(V,E)中的一个顶点序列 { u=vi,0,vi,1, …, vi,m=w}中,(vi,j-1,vi,j)E ,1≤j≤m, 则称从顶点u 到顶点w 之间存在一条路径。 路径上边的数目称作路径长度。 如:长度为3的路径{A,B,C,D} 简单路径:序列中顶点不重复出现的路径。 A 简单回路:序列中第一个顶点和最后一个顶点相同的路径。 E B C D

  13. 对无向图 C B 若(右)图G中任意两个顶点之间都有路径相通,则称此图为连通图; D A E F C B D 若(左)无向图为非连通图,则图中各个极大连通子图称作此图的连通分量。 A E F

  14. 若任意两个顶点之间都存在一条有向路径,则称此有向图为强连通图。若任意两个顶点之间都存在一条有向路径,则称此有向图为强连通图。 对有向图, 否则,其各个强连通子图称作它的强连通分量。 A A B E B E C D C D

  15. 假设一个连通图有 n 个顶点和 e 条边,其中 n-1 条边和 n 个顶点构成一个极小连通子图(生成树)。 对非连通图,则称由各个连通分量的生成树的集合为此非连通图的生成森林。 C B D A E F

  16. 部分操作 • 结构的建立 • 对顶点的操作 • 插入和删除弧 • 遍历

  17. 结构的建立 CreatGraph(&G, V, E) // 按定义(V, VR) 构造图 对顶点的操作 LocateVex(G, u); // 若G中存在顶点u,则返回该顶点在图中“位置” InsertVex(&G, v); //在图G中增添新顶点v。 DeleteVex(&G, v); // 删除G中顶点v及其相关的弧。

  18. 对弧的操作 InsertArc(&G, v, w); // 在G中增添弧<v,w>,若G是无向的,则还增添对称弧<w,v>。 DeleteArc(&G, v, w); //在G中删除弧<v,w>,若G是无向的,则还删除对称弧<w,v>。 遍历 DFSTraverse(G, v); //从顶点v开始深度优先遍历图G,并对访问每个顶点一次且仅一次。 BFSTraverse(G, v); //从顶点v开始广度优先遍历图G,并对访问每个顶点一次且仅一次。

  19. A B F E C D V2 V1 线性结构 V3 A V5 V4 B C D E F 图结构 树结构 不同结构中逻辑关系的对比 在线性结构中,数据元素之间仅具有线性关系; 在树结构中,结点之间具有层次关系; 在图结构中,任意两个顶点之间都可能有关系。

  20. A B F E C D V2 V1 线性结构 V3 A V5 V4 B C D E F 图结构 树结构 不同结构中逻辑关系的对比 在线性结构中,元素之间的关系为前驱和后继; 在树结构中,结点之间的关系为双亲和孩子; 在图结构中,顶点之间的关系为邻接。

  21. 名词和术语复习 网、子图 完全图、稀疏图、稠密图 邻接点、度、入度、出度 路径、路径长度、简单路径、简单回路 连通图、连通分量、强连通图、强连通分量 生成树、生成森林

  22. 6.2 图的存储表示 • 图的数组(邻接矩阵)存储表示 • 图的邻接(链)表存储表示

  23. 一、图的数组(邻接矩阵)存储表示 0 (i,j)E 定义:矩阵的元素为 Aij={ 1 (i,j)E A B C D E F B C A B C D E F A D F E

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

  25. 有向图的邻接矩阵为非对称矩阵 A B C D E A B C D E A B E C D

  26. structArcCell { // 弧的定义 VRType adj; // VRType是顶点关系类型。 // 无权图:0或1,有权图:权值 InfoType *info; // 该弧相关信息(可选) }; enum GraphKind{DG, DN, UDG, UDN}; //有向图, 有向网, 无向图, 无向网 struct MGraph{ // 图的定义 VertexType vexs[MaxVN]; // 顶点信息 ArcCell arcs[MaxVN][MaxVN]; // 弧的信息 int vexnum, arcnum; // 顶点数,弧数 enumGraphKindkind; // 图的种类标志 };

  27. 常见的简单描述如下: struct MGraph{ // 图的定义 int mat[MaxVN][MaxVN]; // 边、弧的信息 int vexnum; // 顶点数 GraphKind kind; // 图的种类标志 };

  28. 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 C A D F E

  29. A B C D E  0 1 2 3 4 1 4  2  3  0 1  2 有向图的邻接表 A B E C F 注意,在有向图的邻接表中不易找到指向该顶点的弧。

  30. A 有向图的逆邻接表 B E C D 在有向图的邻接表中,对每个顶点,链接的是指向该顶点的弧。 A B C D E 3  0 1 2 3 4 3 0  4  2  0 

  31. 弧的结点结构 adjvex info nextarc struct ArcNode { int adjvex(data); // 该弧所指向的顶点的位置 ArcNode *nextarc(next); // 指向下一条弧 InfoType *info; // 该弧相关信息(可选) }; 顶点的结点结构 data firstarc struct VNode { VertexType data; // 顶点信息 ArcNode *firstarc; // 指向第一条依附该顶点的弧 };

  32. 图的定义 struct ALGraph{ // Adjacent List VNodevertices[MaxVN]; int vexnum, arcnum; enum GraphKind kind; // 图的种类标志 };

  33. 无向图邻接表的特点 • 在邻接表中,同一条边对应两个结点; • 顶点v的度:等于v 对应的链表的长度; • 判定两顶点v,w是否邻接:要看v对应的链表中有无对应的结点w(相反判断也行); • 增减边:要在两个单链表插入、删除结点; • 占用存储空间与顶点数、边数均有关;适用于边稀疏的图

  34. 建立邻接表算法描述 // 初始化一个结点总数为num的图, k为图的类型, num 为结点总数 void InitG(ALGraph G, enum GraphKind k, int num){ G.kind=k; G.vexnum=num; G.vertices=new VNode[vexnum]; for(int i=0; i<G.vexnum; i++) { G.vertices[i]. Firstarc=NULL; cin>>G.vertices[i]. data; // 输入结点信息 } } // 有向图(网)增加弧的算法, 将弧(from,to,weight)加入图 void InsertArc(ALGraph G, int from, int to, int weight){ ArcNode *s=new ArcNode; s->weight = weight; s->adjvex = to; s->nextarc = G.vertices[from].firstarc; // 插到链表vertices[from]的头 G.vertices[from].firstarc=s; } 显然,对于无向图(网),只需交换from和to的位置,再进行一次增加弧的操作即可

  35. 课内练习 1、分析并回答下列问题: 1) 图中顶点的度之和与边数之和的关系? 2) 有向图中顶点的入度之和与出度之和的关系? 3) 具有n个顶点的无向图,恰好有n-1条边时一定连通吗? 4) 具有n个顶点的无向图,至少应有多少条边(可能/一定)是一个连通图? 5) 具有n个顶点的有向图,至少应有多少条弧(可能/一定)是一个强连通图?

  36. 课内练习 2、设一有向图G=(V,E),其中V={a,b,c,d,e} , E={<a,b>, <a,d>, <b,a>, <c,b>, <c,d>, <d,e>,<e,a>, <e,b>, <e,c>} 1) 请画出该有向图,并求各顶点的入度和出度。 2) 画出有向图的邻接链表。 3) 画出有向图的逆邻接链表。

  37. 课内思考 小学生游戏 某天,无聊的小杰叫上几个同学玩游戏,其中有比较笨的小凤,比较傻的小雪,可爱的小鑫和自以为是的小练。他们去找聪明的小艺去给他们当裁判。判定谁取得游戏胜利。 而这个游戏是:由小艺给出一个数 a ,再给出一个数 b ,经过规定的运算,使得数 a 变换成数 b ,且使用最少的变换次数 n .谁先说对这个 n ,谁就取得胜利。当然,因为都是小学生,所以假定如果n>6 ,就算是没有答案。那么裁判小艺试图通过编程来使自己尽快的获得答案。请你帮帮他吧...... 问题描述:  题目给出数a(a是一个正整数,不超过50位),再给出目标数b(同样是一个正整数,不超过50位),数的运算有三种:1:使当前数加上19854292:使当前数加上20063:使当前数乘2

  38. 例如:小艺给出数a=1,给出数b=1987437  那么最快我们经过3次指定运算可以使1变成19874371*2=2;(第3种变换)2+1985429=1985431;(第1种变换)1985431+2006=1987437;(第2种变换)再例如:小艺给出数a=1,给出数b=128  那么最快我们经过7次指定运算可以使1变成1281*2*2*2*2*2*2*2=128(均采用第3种变换),但是因为n>6,所以按题不符合要求。

  39. 6.3 图的遍历 从图中某个顶点出发,访遍图中其余顶点,并且使图中的每个顶点仅被访问一次的过程。 • 深度优先搜索 • 广度优先搜索 • 遍历应用举例

  40. 一、深度优先搜索遍历图 连通图的深度优先搜索遍历 从图中某个顶点V0 出发,访问此顶点,然后依次从V0的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和V0有路径相通的顶点都被访问到。

  41. W1、W2和W3均为 V 的邻接点,SG1、SG2 和 SG3 分别为含顶点W1、W2和W3的子图。 V w1 w3 w2 w2 SG3 SG1 SG2 访问顶点 V : foreach (W1、W2、W3 ) 若该邻接点W未被访问, 则从它出发进行深度优先搜索遍历。

  42. 从上页的图解可见: 1. 从深度优先搜索遍历连通图的过程类似于树的先根遍历; 2. 如何判别V的邻接点是否被访问? 解决的办法是:为每个顶点设立一个 “访问标志数组bool visited[vexnum]”。

  43. void DFS(Graph G, int v) { // 从顶点v出发,深度优先搜索遍历连通图 G visited[v] = true; cout<< G.vertices[v].data; for(w=FirstAdjVex(G, v);w存在;w=NextAdjVex(G,v,w)) if (!visited[w]) DFS(G, w); // 对v的尚未访问的邻接顶点w,递归调用DFS } // DFS void DFS(Graph G, int v) { visited[v] = true; cout<< G.vertices[v].data; for(w=0; w<G.vexnum; w++) if (mat[v][w] && !visited[w]) DFS(G, w); } // DFS 若采用邻接矩阵,则算法可写成右边的形式:

  44. 非连通图的深度优先搜索遍历 先将每个顶点的访问标志设为 false, 之后搜索图中每个顶点,若未被访问,则以该顶点为起始点,进行深度优先搜索遍历,否则继续检查下一顶点。 void DFSTraverse(Graph G ) {// 深度优先遍历 fill(visited, visited+G.vexnum, false); // 访问标志数组初始化 for (v=0; v<G.vexnum; ++v) if (!visited[v]) DFS(G, v); // 对尚未访问的顶点调用DFS } 本算法对所有类型的图均适合

  45. 例如: a a b b g g f c c d d e e f h h k k 0 1 2 3 4 5 6 7 8 访问标志: F F F F F F F F F T T T T T T T T T 访问次序: g k e a c h d f b

  46. 二、广度优先搜索遍历图 对连通图,从起始点V到其余各顶点必定存在路径。 w2 w2 w1 w1 其中,V->w1, V->w2, V->w8 的路径长度为1; V V w3 w3 w7 w7 V->w7, V->w3, V->w5 的路径长度为2; w8 w8 w4 w4 w6 w6 V->w6, V->w4 的路径长度为3。 w5 w5

  47. 从图中某个顶点V0出发,并在访问此顶点之后依次访问V0的所有未被访问过的邻接点,之后按这些顶点被访问的先后次序依次访问它们的邻接点,直至图中所有和V0有路径相通的顶点都被访问到。从图中某个顶点V0出发,并在访问此顶点之后依次访问V0的所有未被访问过的邻接点,之后按这些顶点被访问的先后次序依次访问它们的邻接点,直至图中所有和V0有路径相通的顶点都被访问到。 对于非连通图,可能此时尚有顶点未被访问,则另选图中一个未被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。

  48. void BFSTraverse(Graph G){ fill(visited, visited+G.vexnum, false); //初始化visited数组 for (int v=0; v<G.vexnum; ++v ){ if (visited[v]== true ) continue; // v 已经访问 visited[v] = true; cout<<G.vertices[v].data;EnQueue(Q, v); // v入队列 while (!Empty(Q)) { DeQueue(Q, u); // 队头元素出队并置为u foreach ( u的邻接点w ){ if (visited[w] == false){ visited[w]=true; Visit(w); EnQueue(Q, w); } } } } } // BFSTraverse

  49. 也可写成: void BFSTraverse(Graph G) { fill(visited, visited+G.vexnum, false); //初始化visited数组 for (int v=0; v<G.vexnum; ++v ){ if (visited[v] == false) EnQueue(Q, v); // v入队列 while (!Empty(Q)) { DeQueue(Q, u); // 队头元素出队并置为u visited[u]=true; cout<< G.vertices[u].data; foreach ( u的邻接点w ){ if (visited[w] == false) EnQueue(Q, w); } } } } // BFSTraverse

More Related