在算法实现方面要求,熟练掌握图的两种遍历方法,并能够根据图的基本原理解决一些应用问题,如:判定图的连通性、判定是否有环、计算特定路径等。
1,一个连通图采用邻接表作为存储结构,设计一个算法实现从顶点v出发的深度优先遍历的非递归过程。
void DFS1(AGraph *G,int v) { int visited[MAXV],i,j; int St[MAXV],top=-1; ArcNode *p; for (i=0;i<G->n;i++) //访问标志数置初值 visited[i]=0; top++; St[top]=v; //初始顶点进栈 visited[v]=1; //修改访问标志 while (top>-1) //栈不空时循环 { j=St[top];top--; //出栈 printf("%d ",j); //访问节点j p=G->adjlist[j].firstarc; //找第一个邻接点 while (p!=NULL) { if (visited[p->adjvex]==0) //将未访问过的邻接点进栈 { top++; St[top]=p->adjvex; visited[p->adjvex]=1; //修改访问标志 } p=p->nextarc; //找下一个邻接点 } } }
2,设计一个算法,求无向图G(采用邻接表存储)的连通分量个数。
int visited[MAXV]={0}; int Getnum(AGraph *G) //求图G的连通分量 { int i,n=0,visited[MAXVEX]; for (i=0;i<G->n;i++) if (visited[i]==0) { DFS(G,i); //对图G从顶点i开始进行深度优先遍历 n++; //调用DFS的次数即为连通分量数 } return n; }
int visited[MAXV]={0}; int Getnum1(AGraph *G) //求图G的连通分量 { int i,n=0,visited[MAXVEX]; for (i=0;i<G->n;i++) if (visited[i]==0) { BFS(G,i); //对图G从顶点i开始进行广度优先遍历 n++; //调用BFS的次数即为连通分量数 } return n; }
2.1,假设一个无向图是非连通的,采用邻接表作为存储结构,试设计一个算法,输出图中各连通分量的节点序列。
int visited[MAXV]={0}; DFSGraph(AGraph *G) { int i,j=1; //用j记录连通分量的序号 for (i=0;i<G->n;i++) if (visited[i]==0) { printf("第%d个连通分量节点序列:",j++); DFS(G,i); //调用前面的深度优先遍历算法 } }
int visited[MAXV]={0}; BFSGraph(AGraph *G) { int i,j=1; //用j记录连通分量的序号 for (i=0;i<G->n;i++) if (visited[i]==0) { printf("第%d个连通分量节点序列:",j++); BFS(G,i); //调用前面的广度优先遍历算法 } }
3,假设无向图G采用邻接表存储,设计一个算法,判断图G是否为连通图。若为连通图返回1;否则返回0。
void DFS2(AGraph *G,int v,int &vn,int &en) { ArcNode *p; visited[v]=1;vn++; //遍历过的顶点数增1 p=G->adjlist[v].firstarc; while (p!=NULL) { en++; //遍历过的边数增1 if (visited[p->adjvex]==0) DFS2(G,p->adjvex,vn,en); p=p->nextarc; } } int GIsTree(AGraph *G) //判断无向图G是否是一棵树 { int vn=0,en=0,i; for (i=0;i<G->n;i++) visited[i]=0; DFS2(G,1,vn,en); if (vn==G->n && en==2*(G->n-1)) return 1; //遍历顶点为G->n个,边数为2(g->n-1),则为树 else return 0; }
3.1,设计一个算法,判断一个无向图G是否是一棵树。若是树,返回1;否则返回0。
void DFS2(AGraph *G,int v,int &vn,int &en) { ArcNode *p; visited[v]=1;vn++; //遍历过的顶点数增1 p=G->adjlist[v].firstarc; while (p!=NULL) { en++; //遍历过的边数增1 if (visited[p->adjvex]==0) DFS2(G,p->adjvex,vn,en); p=p->nextarc; } } int GIsTree(AGraph *G) //判断无向图G是否是一棵树 { int vn=0,en=0,i; for (i=0;i<G->n;i++) visited[i]=0; DFS2(G,1,vn,en); if (vn==G->n && en==2*(G->n-1)) return 1; //遍历顶点为G->n个,边数为2(g->n-1),则为树 else return 0; }
4,假设一个连通图采用邻接表作为存储结构,试设计一个算法,判断其中是否存在回路。
void Cycle(AGraph *G,int v,bool &has) { //调用时has置初值false ArcNode *p; int w; visited[v]=1; //置已访问标记 p=G->adjlist[v].firstarc; //p指向顶点v的第一个邻接点 while (p!=NULL) { w= p->adjvex; if (visited[i]==0) //若顶点w未访问,递归访问它 Cycle(G,w,has); else //又找到了已访问过的顶点说明有回路 has=true; p=p->nextarc; //找下一个邻接点 } }
5,假设图G采用邻接表存储,设计一个算法判断图G中顶点u到顶点v之间是否有简单路径。
void ExistPath(AGraph *G,int u,int v,int &has) { //has表示u到v是否有路径,初值为0 int w; ArcNode *p; visited[u]=1; //置已访问标记 if (u==v) //找到了一条路径 { has=1; return; } p=G->adjlist[u].firstarc; //p指向顶点u的第一个相邻点 while (p!=NULL) { w=p->adjvex; //w为顶点u的相邻顶点 if (visited[w]==0) //若w顶点未访问,递归访问它 ExistPath(G,w,v,has); p=p->nextarc; //p指向顶点v的下一个相邻点 } }
6,假设图G采用邻接表存储,设计一个算法,输出图G中从顶点u到v的所有简单路径。
void FindPath(AGraph *G,int u,int v,int path[ ],int d) //d是到当前为止已走过的路径长度,调用时初值为-1 { int w,i; ArcNode *p; d++; //路径长度增1 path[d]=u; //将当前顶点添加到路径中</p> visited[u]=1; //置已访问标记 if (u==v) //找到一条路径则输出 { for (i=0;i<=d;i++) printf("%2d",path[i]); printf("\n"); } p=G->adjlist[u].firstarc; //p指向v的第一个相邻点 while (p!=NULL) { w=p->adjvex; //w为顶点u的相邻顶点 if (visited[w]==0) //若w顶点未访问,递归访问它 FindPath(G,w,v,path,d); p=p->nextarc; //p指向v的下一个相邻点 } visited[u]=0; //恢复环境,使该顶点可重新使用 }
7,假设不带权图G采用邻接表存储,设计一个算法,采用BFS方式输出图G中从顶点u到v的最短路径。
typedef struct { int data; //顶点编号 int parent; //前一个顶点的位置 } QUERE; //非循环队列类型 void ShortPath(AGraph *G,int u,int v) { //输出从顶点u到顶点v的最短逆路径 ArcNode *p; int w,i; QUERE qu[MAXV]; //非环形队列 int front=-1,rear=-1; //队列的头、尾指针 int visited[MAXV]; for (i=0;i<G->n;i++) //访问标记置初值0 visited[i]=0; rear++; //顶点u进队 qu[rear].data=u; qu[rear].parent=-1; visited[u]=1; while (front!=rear) //队不空循环 { front++; //出队顶点w w=qu[front].data; if (w==v) //找到v时输出路径之逆并退出 { i=front; //通过队列输出逆路径 while (qu[i].parent!=-1) { printf("%d<-",qu[i].data); i=qu[i].parent; } printf("%2d\n",qu[i].data); break; } p=G->adjlist[w].firstarc; //找w的第一个邻接点 while (p!=NULL) { if (visited[p->adjvex]==0) { visited[p->adjvex]=1; rear++; //将w的未访问过的邻接点进队 qu[rear].data=p->adjvex; qu[rear].parent=front; } p=p->nextarc; //找w的下一个邻接点 } } }