1、数据结构与算法实验指导 V2014常熟理工学院计算机科学与工程学院 1实 验 七 图【实验目的】1、掌握图的邻接矩阵和邻接表表示。2、掌握图的深度优先和广度优先搜索方法。3、掌握图的最小生成树 Prim 算法。4、掌握图的拓扑排序算法。5、掌握图的单源最短路径 dijkstra 算法。【实验学时】4-6 学时【实验预习】回答以下问题:1、写出图 7-1 无向图的邻接矩阵表示。ABCGFDEH图 7-1 无向图 G12、写出图 7-2 有向图的邻接表表示。EFBACD图 7-2 有向图 G23、写出图 7-1 的深度优先搜索序列和广度优先搜索序列。深度:ABDHECFG广度:ABCFDEGH4、
2、写出图 7-2 的拓扑序列,说明该有向图是否有环?5、根据图 7-3,写出其最小生成树。数据结构与算法实验指导 V2014常熟理工学院计算机科学与工程学院 2CFDBAE6215566345图 7-3 无向带权图 G36、根据图 7-4,求从顶点 A 到其他顶点的单源最短路径。ABCDEF1 0 06 02 03 01 05 01 05图 7-4 有向带权图 G4【实验内容和要求】1、 编写程序 exp7_1.c,实现图的邻接矩阵存储及图的深度优先搜索和广度优先搜索。以图 7-1 的无向图为例,补充完整程序,调试运行并写出运行结果。运行结果:(包括输入数据)数据结构与算法实验指导 V2014常
3、熟理工学院计算机科学与工程学院 3exp7_1.c 参考程序如下:#include#define N 20#define TRUE 1#define FALSE 0int visitedN; /*访问标志数组 */typedef struct /*辅助队列的定义 */int dataN;int front,rear;queue;typedef struct /*图的邻接矩阵表示 */int vexnum,arcnum;char vexsN;int arcsNN;MGraph;void createGraph(MGraph *g); /*建立一个无向图的邻接矩阵*/void dfs(int i,
4、 MGraph *g); /*从第 i 个顶点出发深度优先搜索 */void tdfs(MGraph *g); /*深度优先搜索整个图*/void bfs(int k, MGraph *g); /*从第 k 个顶点广度优先搜索*/void tbfs(MGraph *g); /*广度优先搜索整个图*/void init_visit(); /*初始化访问标识数组*/数据结构与算法实验指导 V2014常熟理工学院计算机科学与工程学院 4void createGraph(MGraph *g) /*建立一个无向图的邻接矩阵*/int i=0,j,e=0;char v;g-vexnum=0;g-arcnu
5、m=0;printf(“n 输入顶点序列(以#结束) :n“);while (v=getchar()!=#) g-vexsi=v; /*读入顶点信息*/i+;g-vexnum=i; /*顶点数目*/for (i=0;ivexnum;i+) /*邻接矩阵初始化*/for (j=0;jvexnum;j+)g-arcsij=0;/*(1)-邻接矩阵元素初始化为 0*/printf(“n 输入边的信息(顶点序号,顶点序号) ,以(-1,-1)结束:n“);scanf(“%d,%d“, /*读入边(i,j)*/while (i!=-1) /*读入 i 为1 时结束*/g-arcsij=1; /*(2)-
6、i,j 对应边等于 1*/g-arcsji=1;e+;scanf(“%d,%d“,g-arcnum=e; /*边数目*/* createGraph */*(3)- 从第 i 个顶点出发深度优先搜索,补充完整算法*/void dfs(int i, MGraph *g)int j;printf(“%c“,g-vexsi);visitedi=1;for(j=0;jvexnum;j+)if(g-arcsij=1/* dfs */void tdfs(MGraph *g) /*深度优先搜索整个图*/int i;printf(“n 从顶点%C 开始深度优先搜索序列:“,g-vexs0);for (i=0;i
7、vexnum;i+)if (!visitedi) /*(4)- 对尚未访问过的顶点进行深度优先搜索*/dfs(i,g);printf(“n“);数据结构与算法实验指导 V2014常熟理工学院计算机科学与工程学院 5/*tdfs*/void bfs(int k, MGraph *g) /*从第 k 个顶点广度优先搜索*/int i,j;queue qlist,*q;q=q-rear=0;q-front=0;printf(“%c“,g-vexsk);visitedk=TRUE;q-dataq-rear=k;q-rear=(q-rear+1)%N;while (q-rear!=q-front) /*
8、当队列不为空,进行搜索*/i=q-dataq-front;q-front=(q-front+1)%N;for (j=0;jvexnum;j+)if (g-arcsij=1)visitedj=TRUE;q-dataq-rear=j; /*(5)-刚访问过的结点入队 */q-rear=(q-rear+1)%N; /*(6)-修改队尾指针*/*bfs*/void tbfs(MGraph *g) /*广度优先搜索整个图*/int i;printf(“n 从顶点%C 开始广度优先搜索序列:“,g-vexs0);for (i=0;ivexnum;i+)if (visitedi!=TRUE)bfs(i,g)
9、; /*从顶点 i 开始广度优先搜索*/printf(“n“);/*tbfs*/void init_visit() /*初始化访问标识数组*/int i;for (i=0;i#include数据结构与算法实验指导 V2014常熟理工学院计算机科学与工程学院 7#define N 20/*图的邻接表:邻接链表结点 */typedef struct EdgeNodeint adjvex; /*顶点序号*/struct EdgeNode *next; /*下一个结点的指针*/ EdgeNode;/*图的邻接表:邻接表*/typedef struct VNodechar data; /*顶点信息*/i
10、nt ind; /*顶点入度*/struct EdgeNode *link; /*指向邻接链表指针*/ VNode;typedef struct ALgraph /*图的邻接表*/int vexnum,arcnum; /*顶点数、弧数*/VNode adjlistN;ALGraph;void createGraph_list(ALGraph *g); /*建立有向图的邻接表*/void topSort(ALGraph *g); /*拓扑排序 */*建立有向图的邻接表*/void createGraph_list(ALGraph *g)int i,j,e;char v;EdgeNode *s;i
11、=0;e=0;printf(“n 输入顶点序列(以#结束) :n“);while(v=getchar()!=#) g-adjlisti.data=v; /*读入顶点信息*/g-adjlisti.link=NULL;g-adjlisti.ind=0;i+;g-vexnum=i; /*建立邻接链表*/printf(“n 请输入弧的信息(顶点序号,顶点序号) ,以(-1,-1)结束:n“);scanf(“%d,%d“,while(i!=-1) s=(struct EdgeNode*)malloc(sizeof(EdgeNode);s-adjvex=j;s-next=g-adjlisti.link;
12、/*(1)s 插入链表*/g-adjlisti.link=s;g-adjlistj.ind+; /*(2)顶点 j 的入度加 1*/e+;数据结构与算法实验指导 V2014常熟理工学院计算机科学与工程学院 8scanf(“%d,%d“,g-arcnum=e;/*createGraph_list*/void topSort(ALGraph *g) /*拓扑排序*/int i,j,k,top=0,m=0,sN; /*m 为拓扑排序输出的结点数*/EdgeNode *p;for(i=0; ivexnum; i+)if(g-adjlisti.ind=0) /*(3)入度为 0 的顶点入栈 */stop
13、+=i;printf(“n 输出拓扑序列:“);while(top0) j=s-top;printf(“%c“,g-adjlistj.data);m+;p=g-adjlistj.link;while(p!=NULL) k=p-adjvex;g-adjlistk.ind-; /*顶点 k 入度减 1*/if(g-adjlistk.ind=0) /*顶点 k 入度为 0,进栈*/stop+=k;p=p-next;printf(“n 共输出%d 个顶点n“,m);if(mvexnum) /*(4)当输出顶点数小于图的顶点数,表示有环*/printf(“图中有环!“);elseprintf(“图中无环
14、!“);/*topSort*/int main()ALGraph g;int i;EdgeNode *s;printf(“*图的邻接表存储结构和拓扑排序*n“);printf(“n1-输入图的基本信息:n“);createGraph_list( /*创建图的邻接表存储结构*/printf(“n2-图的邻接表:“);for(i=0; i%d“,s-adjvex);s=s-next;printf(“n“);printf(“n3-根据图的邻接表实现拓扑排序:n“);topSort( /*进行拓扑排序 */return 0;(3)调试下面给出的图的信息,写出运行结果,画出该有向图。ABCDEF#1,0
15、1,32,12,53,23,43,54,05,05,15,4-1,-1数据结构与算法实验指导 V2014常熟理工学院计算机科学与工程学院 103、编写程序 exp7_3.c,实现带权图的存储、图的最小生成树及单源最短路径算法。以图 7-3(求该图最小生成树)和图 7-4(求该图的单源最短路径)为例,补充完整程序,调试运行并写出运行结果。运行结果:(包括输入数据)exp7_3.c 程序代码参考如下:#include #define N 20#define TRUE 1#define INF 32766 /*邻接矩阵中的无穷大元素 */#define INFIN 32767 /*比无穷大元素大的数
16、*/typedef struct/*图的邻接矩阵表示 */int vexnum,arcnum;char vexsN;int arcsNN;MGraph;void printPath(MGraph g, int startVex, int EndVex, int pathN); /*打印最短路径*/数据结构与算法实验指导 V2014常熟理工学院计算机科学与工程学院 11void createMGraph_w(MGraph *g, int flag); /*建带权图的邻接矩阵*/void prim(MGraph *g, int u); /*求最小生成树 Prim 算法,u 为出发顶点*/void
17、dijkstra(MGraph g, int v); /*dijkstra 算法求单源最短路径 */void createMGraph_w(MGraph *g, int flag)/*建带权图的邻接矩阵,若 flag 为 1 则为无向图,flag 为 0 为有向图*/int i,j,w;char v;g-vexnum=0;g-arcnum=0;i=0;printf(“n 输入顶点序列(以#结束) :n“);while(v=getchar()!=#)g-vexsi=v; /*读入顶点信息*/i+;g-vexnum=i;for(i=0; iarcsij=INF;printf(“n 输入边的信息:(
18、顶点,顶点,权值) ,以(-1,-1,-1)结束n“);scanf(“%d,%d,%d“, /*读入边(i,j,w)*/while(i!=-1) /*读入 i 为1 时结束*/g-arcsij=w;if(flag=1)g-arcsji=w;scanf(“%d,%d,%d“,/*createMGraph_w*/void prim(MGraph *g, int u)/*求最小生成树 Prim 算法,u 为出发顶点*/int lowcostN,closestN,i,j,k,min;for(i=0; ivexnum; i+) /*求其他顶点到出发顶点 u 的权*/lowcosti=_;/*(1)-顶点
19、 i 到 u 的代价最小的边权值 */closesti=u;lowcostu=0;printf(“n 最小生成树:n“);for(i=1; ivexnum; i+) /*循环求最小生成树中的各条边*/min=INFIN;for(j=0; jvexnum; j+) /*选择得到一条代价最小的边*/if(lowcostj!=0 /*输出该边*/lowcostk=0; /*顶点 k 纳入最小生成树 */for(j=0; jvexnum; j+) /*求其他顶点到顶点 k 的权*/if(g-arcskj!=0i %c(%d) “,g.vexsi,g.arcsji); /输出 j 到 k 路径顶点 if
20、lagi=1;j=i;k=stack-top;break;elseif (i!=k) stacktop+=i;if (flagk=0) printf(“- %c(%d)“,g.vexsk,g.arcsjk);void dijkstra(MGraph g, int v)/*dijkstra 算法求单源最短路径*/int sN, pathNN,distN;int mindis,i,j,u,k;for(i=0; i到各顶点的最短路径n“,g.vexsv);for (i=0;i顶点%c:“,g.vexsv,g.vexsi);if (disti=INF|disti=0)printf(“无路径“);els
21、e printf(“%d “,disti);printf(“经过顶点:“);printPath(g,v,i,path); /输出 v 到 i 的路径/*dijkstra*/int main()int select;数据结构与算法实验指导 V2014常熟理工学院计算机科学与工程学院 14MGraph ga;do printf(“n*MENU*n“);printf(“ 1. 图的最小生成树-Prim 算法n“);printf(“ 2. 图的单源最短路径-dijstra 算法n“);printf(“ 0. EXIT“);printf(“n*MENU*n“);printf(“ninput choice
22、:“);scanf(“%d“,getchar();switch(select)case 1:printf(“n1-图的最小生成树-Prim 算法n“);printf(“n 输入带权图的基本信息:n“);createMGraph_w(prim(break;case 2:printf(“n2-图的单源最短路径-dijstra 算法n“);printf(“n 输入带权图的基本信息:n“);createMGraph_w(dijkstra(ga,0);break;default:break;while(select);return 0;【拓展实验】4、编写算法,实现最小生成树的 Kruskal 算法。提
23、示:Kruskal 算法实现的基本步骤:(1)需要对图中所有的边进行排序,因此需要借助一个辅助数组 edge 来存储按权值由小到大排序的边。包括边的权值、边的起点和终点。(2)每加入一条边,需要判断该边的两个顶点是否处在同一连通分量上,可以利用数组 parents 来表示各顶点的状况,parentsi=i ;初始值设置为各自的顶点值,表示各顶点自成一连通分量。当加入该边,需要对该边的边头顶点和边尾顶点的 parents 值相等。5、编写算法,实现图的最短路径 Floyd 算法。提示:弗洛伊德算法的基本步骤:对有向图采用带权邻接矩阵存储,同时定义一个二维数组数据结构与算法实验指导 V2014常熟
24、理工学院计算机科学与工程学院 15ANN存放顶点 i 到 j 的最短路径。(1)初始化 Aij=arcsij;(2)考虑 vi 和 vj 之间的路径,是否存在途经 vk 的路径( vi,vk,vj),若存在,比较 Aik+AKj和 Aij的距离,较小送 Aij;重复上步,取 vk 为图中所有顶点,直到比较完毕。同时还必须定义一个矩阵记录最短路径经过的顶点。6、编写算法,实现图的关键路径算法。提示:基于邻接矩阵的关键路径的求解步骤:(1)对 AOE 网进行拓扑排序,同时按拓扑序列的次序求出各顶点事件的最早发生时间ve,若网中存在回路,则算法终止,否则执行步骤(2);(2)按拓扑序列的逆序求出各顶点事件的最迟发生时间 vl;(3)根据各顶点事件的 ve 和 vl 值,求出各顶点活动 ai 的最早发生时间 e(i)和最迟发生时间 l(i)。若 e(i)l(i) ,则 ai 为关键活动。【实验小结】