1 / 123

第七章 图

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

Download Presentation

第七章 图

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 图的定义和术语 • 图(Graph)——图G是由两个集合V(G)和E(G)组成的,记为G=(V,E) 其中:V(G)是顶点的非空有限集 E(G)是边的有限集合,边是顶点的无序对或有序对 • 有向图——有向图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)。

  2. 例1: 2 4 5 1 3 6 G1 例2: 1 5 7 3 2 4 6 G2 图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)}

  3. 有向完全图——n个顶点的有向图最大边数是n(n-1)有向完全图——n个顶点的有向图最大边数是n(n-1) • 无向完全图——n个顶点的无向图最大边数是n(n-1)/2 • 权——与图的边或弧相关的数叫~ • 网——带权的图叫~ • 子图——如果图G(V,E)和图G’(V’,E’),满足: V’V,且E’E,则称G’为G的子图。 • 顶点的度 • 无向图中,顶点的度为与每个顶点相连的边数 • 有向图中,顶点的度分成入度与出度 入度:以该顶点为头的弧的数目 出度:以该顶点为尾的弧的数目

  4. 路径——路径是顶点的序列V={Vi0,Vi1,……Vin},满足(Vij-1,Vij)E 或 < Vij-1,Vij>E,(1<jn) • 路径长度——沿路径边的数目或沿路径各边权值之和 • 回路——第一个顶点和最后一个顶点相同的路径叫~ • 简单路径——序列中顶点不重复出现的路径叫~ • 简单回路——除了第一个顶点和最后一个顶点外,其余顶点不重复出现的回路叫~ • 连通——从顶点V到顶点W有一条路径,则说V和W是连通的 • 连通图——图中任意两个顶点都是连通的叫~ • 连通分量——非连通图的每一个连通部分叫~ • 强连通图——有向图中,如果对每一对Vi,VjV, ViVj,从Vi到Vj 和从Vj到Vi都存在路径,则称G是~

  5. 例 例 2 2 4 4 5 5 无向完全图 有向完全图 1 1 3 3 6 6 G1 2 2 1 3 1 3 例 1 5 7 图与子图 3 2 4 6 G2 5 顶点5的度:3 顶点2的度:4 顶点2入度:1 出度:3 顶点4入度:1 出度:0 3 6

  6. 2 4 5 1 3 6 G1 例 1 5 7 3 2 4 6 G2 路径:1,2,3,5,6,3 路径长度:5 简单路径:1,2,3,5 回路:1,2,3,5,6,3,1 简单回路:3,5,6,3 路径:1,2,5,7,6,5,2,3 路径长度:7 简单路径:1,2,5,7,6 回路:1,2,5,7,6,5,2,1 简单回路:1,2,3,1

  7. 2 4 5 1 3 6 例 例 2 4 5 5 1 3 6 3 6 连通图 强连通图 非连通图 连通分量

  8. V3 ^ V4 ^ V2 ^ ^ V1 1 2 例 V5 ^ V2 ^ V1 V3 V4 ^ 1 2 3 4 3 G1 4 5 G2 7.2 图的存储结构 (1)多重链表法

  9. 例:       1 2 例:  1 2  3 4 3      G1  4 5  G2    (2)邻接矩阵法——表示顶点间相联关系的矩阵 定义:设G=(V,E)是有n1个顶点的图,G的邻接矩阵A是具有以下性质的n阶方阵。

  10. 特点: • 无向图的邻接矩阵对称,可压缩存储;有n个顶点的无向图需存储空间为n(n+1)/2; • 有向图邻接矩阵不一定对称;有n个顶点的有向图需存储空间为n²; • 无向图中顶点Vi的度TD(Vi)是邻接矩阵A中第i行元素之和; • 有向图中, • 顶点Vi的出度是A中第i行元素之和; • 顶点Vi的入度是A中第i列元素之和; • 网络的邻接矩阵可定义为:

  11. 5 例 1 2 3     8 7 4 5 1 6 3 4 2      

  12. (3)关联矩阵法——表示顶点与边的关联关系的矩阵(3)关联矩阵法——表示顶点与边的关联关系的矩阵 • 定义:设G=(V,E)是有n1个顶点,e0条边的图,G的关联矩阵A是具有以下性质的ne阶矩阵。

  13. 1 2 4 3 例 1 4 2 1 2 例 6 3 5 1 2 3 4 3 G1 4 5 G2 1 2 3 4     1 2 3 4 6 5     

  14. 5 3 例 A B C 2 4 6 1 D 1 2 3 4 5 6 A B C D

  15. 特点 • 关联矩阵每列只有两个非零元素,是稀疏矩阵;n越大,零元素比率越大; • 无向图中顶点Vi的度TD(Vi)是关联矩阵A中第i行元素之和; • 有向图中, • 顶点Vi的出度是A中第i行中“1”的个数; • 顶点Vi的入度是A中第i行中“-1”的个数;

  16. typedef struct node { int adjvex; //邻接点域,存放与Vi邻接的点在表头数组中的位置 struct node *next; //链域,指示下一条边或弧 }JD; adjvex next 表头接点: typedef struct tnode { int vexdata; //存放顶点信息 struct node *firstarc; //指示第一个邻接点 }TD; TD ga[M]; //ga[0]不用 vexdata firstarc (4)邻接表法 • 实现:为图中每个顶点建立一个单链表,第i个单链表中的结点表示依附于顶点Vi的边(有向图中指以Vi为尾的弧)

  17. vexdata firstarc adjvex next 1 例 ^ 2 a ^ 3 b ^ 4 c ^ d 5 2 1 2 3 4 3 2 4 1 4 2 3 1 3 5 a b 例 vexdata firstarc adjvex next a b 1 a ^ c d c ^ b 2 G1 3 c ^ d e G2 4 d ^ 5 e ^

  18. a b c d 3 1 1 4 a b vexdata adjvex firstarc next 1 ^ c d 2 ^ G1 3 ^ 4 ^ 特点 • 无向图中顶点Vi的度为第i个单链表中的结点数; • 有向图中 • 顶点Vi的出度为第i个单链表中的结点个数; • 顶点Vi的入度为整个单链表中邻接点域值是i的结点个数; • 逆邻接表:有向图中对每个结点建立以Vi为头的弧的单链表;

  19. 弧结点: typedef struct arcnode { int tailvex, headvex; //弧尾、弧头在表头数组中位置 struct arcnode *hlink;//指向弧头相同的下一条弧 struct arcnode *tlink; //指向弧尾相同的下一条弧 }AD; tailvex headvex hlink tlink 顶点结点: typedef struct dnode { int data; //存与顶点有关信息 struct arcnode *firstin;//指向以该顶点为弧头的第一个弧结点 struct arcnode *firstout; //指向以该顶点为弧尾的第一个弧结点 }DD; DD g[M]; //g[0]不用 data firstin firstout (5)有向图的十字链表表示法

  20. 例: 1 2 1 3 1 a ^ b 2 a b ^ 3 c c d 3 1 3 4 ^ ^ d ^ ^ ^ ^ 4 4 3 4 1 4 2

  21. 边结点: typedef struct node { int mark; //标志域 int ivex, jvex; //该边依附的两个顶点在表头数组中位置 struct node *ilink, *jlink; //分别指向依附于ivex和jvex的下一条边 }JD; mark ivex ilink jvex jlink 顶点结点: typedef struct dnode { int data; //存与顶点有关的信息 struct node *firstedge; //指向第一条依附于该顶点的边 }DD; DD ga[M]; //ga[0]不用 data firstedge (6)无向图的邻接多重表表示法

  22. ^ ^ 5 2 5 3 3 2 3 4 1 4 1 2 1 a 例: b 2 a b 3 c c 4 d ^ ^ ^ d e 5 e

  23. 课外学习 • 看书 P156——166 • 思考题 7.1 • 上机 建立邻接表表示的图

  24. 建立邻接表表示的图 #include<stdio.h> #include<stdlib.h> #define M 20 #define NULL 0 typedef char datatype; typedef struct node //链表中结点 { int adjvex; //邻接点域,存放与Vi邻接的点在表头数组中的位置 struct node *next; //链域,指示下一条边或弧 }JD; typedef struct tnode //表头接点: { datatype vexdata; //存放顶点信息 struct node *firstarc; //指示第一个邻接点 }TD; TD ga[M]; //ga[0]不用

  25. scanf("%c%*c%c", &v1, &v2); • getchar(); • i = locvertex(g, v1);//求v1在表头数组下标j = locvertex(g, v2);//求v2在表头数组下标p = (JD*)malloc(sizeof(JD)); • p->adjvex = j; • p->next = g[i].firstarc; • g[i].firstarc = p; //插入表头 • p = (JD*)malloc(sizeof(JD)); • p->adjvex = i; • p->next = g[j].firstarc; • g[j].firstarc = p; • } • } void createljb(TD g[],int n,int e) { int i,j,k; datatype v1, v2; JD *p; printf("\n输入顶点的数据:\n"); for(k = 1; k<=n ;k++) { scanf("%c", &g[k].vexdata); g[k].firstarc = NULL; } getchar(); //吸收回车 printf("\n输入图中各弧:\n"); for(k=1; k<=e;k++) {

  26. //求v在表头数组g中的下标 int locvertex(TD g[],datatype v) { int k; for (k = 1; k < M; k++) if(g[k].vexdata == v) return k; return -1; } void main() { int n,e,k; printf("\n输入图中顶点的个数 n 和弧数 e:\n"); scanf("%d%*c%d", &n, &e); createljb(ga,n,e); }

  27. V1 例 V2 V3 V4 V5 V6 V7 V8 7.3 图的遍历 (1)深度优先遍历(DFS) • 方法:从图的某一顶点V0出发,访问此顶点;然后依次从V0的未被访问的邻接点出发,深度优先遍历图,直至图中所有和V0相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作起点,重复上述过程,直至图中所有顶点都被访问为止。 深度遍历:V1 V2 V4  V8 V5 V3 V6 V7

  28. V1 例 V2 V3 V4 V5 V6 V7 V8 V1 例 V3 V2 V5 V6 V4 V8 V7 深度遍历:V1 V2 V4  V8 V5 V6 V3 V7 深度遍历:V1 V2 V4  V8 V5 V6 V3 V7

  29. V1 例 V2 V3 V4 V5 V6 V7 V8 深度遍历:V1 V2 V4  V8 V3 V6 V7 V5

  30. 开始 标志数组初始化 i=0 Vi访问过 N DFS Y Vi=Vi+1 Vi==Vexnums N Y 结束 开始 • 深度优先遍历算法 • 递归算法 访问V0,置标志 求V0邻接点 有邻接点w N Y 结束 Y W访问过 N 求下一邻接点 wV0 DFS

  31. void dfs(TD g[ ],int v,int visited[]) { JD *w; int i; printf("%d ",v); visited[v]=1; w=g[v].firstarc; while(w!=NULL) { i=w->adjvex; if(visited[i]==0) dfs(g,i,visited); w=w->next; } } void traver(TD g[ ],int n) { int i; static int visited[M]; for(i=1;i<=n;i++) visited[i]=0; for(i=1;i<=n;i++) if(visited[i]==0) dfs(g,i,visited); }

  32. vexdata firstarc adjvex next 1 1 ^ ^ 2 2 3 3 ^ 5 3 6 3 7 2 8 2 3 6 7 5 1 4 8 2 1 4 4 4 ^ V1 例 5 5 ^ V2 V3 6 6 ^ 7 7 V4 V5 V6 V7 ^ 8 8 ^ V8 深度遍历:V1 V3  V7  V6  V2  V5  V8  V4

  33. V1 例 V2 V3 V4 V5 V6 V7 V8 • 广度优先遍历(BFS) • 方法:从图的某一顶点V0出发,访问此顶点后,依次访问V0的各个未曾访问过的邻接点;然后分别从这些邻接点出发,广度优先遍历图,直至图中所有已被访问的顶点的邻接点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作起点,重复上述过程,直至图中所有顶点都被访问为止。 广度遍历:V1 V2 V3  V4 V5 V6 V7 V8

  34. V1 例 V2 V3 V4 V5 V6 V7 V8 V1 例 V3 V2 V5 V6 V4 V8 V7 广度遍历:V1 V2 V3  V4 V5 V6 V7 V8 广度遍历:V1 V2 V3  V4 V5 V6 V7 V8

  35. V1 例 V2 V3 V4 V5 V6 V7 V8 广度遍历:V1 V2 V3  V4 V6 V7 V8 V5

  36. 开始 标志数组初始化 i=0 Vi访问过 N BFS Y i=i+1 i==Vexnums N Y 结束 广度优先遍历算法

  37. 开始 访问Vi,置标志 初始化队列 Vi入队 Y 队列空吗 a N 访问w,置标志 队头V出队 结束 求Vi邻接点w w入队 N w存在吗 Vi下一邻接点w Y Y w访问过 N BFS a

  38. void traver(TD g[],int n) { int i; static int visited[M]; for(i=1;i<=n;i++) visited[i]=0; for(i=1;i<=n;i++) if(visited[i]==0) bfs(g,i,visited); }

  39. void bfs(TD g[],int v,int visited[]){ int qu[M],f=0,r=0; JD *p; printf("%d\n",v); visited[v]=1; qu[0]=v; while(f<=r) { v=qu[f++]; p=g[v].firstarc; while(p!=NULL) { v=p->adjvex; if(visited[v]==0) { visited[v]=1; printf("%d\n",v); qu[++r]=v; } p=p->next; } } }

  40. 1 2 3 4 5 f f f vexdata firstarc 5 4 5 3 4 5 2 1 1 3 2 1 adjvex next ^ 1 1 1 4 2 2 4 3 ^ 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 3 3 ^ r r r 4 4 ^ 遍历序列:1 遍历序列:1 4 遍历序列:1 4 3 5 5 ^

  41. 1 4 3 2 3 2 2 3 4 5 遍历序列:1 4 3 2 遍历序列:1 4 3 2 f f f vexdata firstarc 3 1 1 4 3 5 5 5 1 2 2 4 adjvex next ^ 1 1 2 2 3 2 5 ^ 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 3 3 ^ r r r 4 4 ^ 遍历序列:1 4 3 2 5 5 5 ^

  42. 1 2 3 4 5 f f f vexdata firstarc 1 5 3 4 1 5 2 2 3 4 5 1 adjvex next ^ 1 1 2 2 ^ 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 5 2 5 3 3 ^ r r r 4 4 ^ 5 5 ^ 遍历序列:1 4 3 2 5 遍历序列:1 4 3 2 5 遍历序列:1 4 3 2 5

  43. G K I H 7.4 图的连通问题 • 生成树 • 定义:所有顶点均由边连接在一起,但不存在回路的图叫~ • 深度优先生成树与广度优先生成树 • 生成森林:非连通图每个连通分量的生成树一起组成非连通图的~ • 说明 • 一个图可以有许多棵不同的生成树 • 所有生成树具有以下共同特点: • 生成树的顶点个数与图的顶点个数相同 • 生成树是图的极小连通子图 • 一个有n个顶点的连通图的生成树有n-1条边 • 生成树中任意两个顶点间的路径是唯一的 • 在生成树中再加一条边必然形成回路 • 含n个顶点n-1条边的图不一定是生成树

  44. V1 V1 V2 V3 V2 V3 V4 V5 V6 V7 V4 V5 V6 V7 V1 V8 V1 V8 V2 V3 V2 V3 V4 V6 V4 V5 V6 V7 V1 例 V8 V7 V2 V3 V8 广度优先生成树 V5 V4 V5 V6 V7 深度优先生成树 V8 深度遍历:V1 V2 V4  V8 V5 V3 V6 V7 广度遍历:V1 V2 V3  V4 V5 V6 V7 V8

  45. A B C D E F G H D A I K L C F E J M L M B J G K I 深度优先生成森林 H

  46. V1 V2 V3 V4 V5 V6 V7 V8 课外学习 • 看书 p167——176 • 思考题 1、写出下图的深度优先搜索序列、广度优先搜索序列 2、题集 7.7

  47. 7 1 2 7 5 9 13 24 6 5 10 17 12 3 4 18 要在n个城市间建立通信联络网, 顶点——表示城市 权——城市间建立通信线路所需花费代价 希望找到一棵生成树,它的每条边上的权值之和(即建立 该通信网所需花费的总代价)最小———最小代价生成树 • 最小生成树 • 问题提出 • 问题分析 n个城市间,最多可设置n(n-1)/2条线路 n个城市间建立通信网,只需n-1条线路 问题转化为:如何在可能的线路中选择n-1条,能把 所有城市(顶点)均连起来,且总耗费 (各边权值之和)最小

  48. 构造最小生成树方法 • 方法一:普里姆(Prim)算法 • 算法思想:设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²)

  49. 1 1 例 5 6 1 1 5 2 4 5 5 3 3 3 3 2 4 6 6 5 6 1 1 1 1 1 1 2 4 4 1 1 2 4 3 5 3 3 2 2 3 4 2 4 4 4 5 6 6 6 6 1

  50. #define M 30#define MAX 100void minispantree_PRIM(int ad[][M],int n){ int i,j,k,p,q,wm; q=p=n-1; ad[q][q]=1; for(k=0;k<(n-1);k++) //找n-1条边 { wm=MAX; for(i=0;i<n;i++) //按列遍历邻接矩阵 if(ad[i][i]==1) //Vi属于集合U、

More Related