实验五 图(to student)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验五图
一、实验目的
1. 掌握图的基本存储方法;
2. 掌握有关图的操作算法并用高级语言实现;
3. 熟练掌握图的两种搜索路径的遍历方法。
二、实验内容
假设以一个带权有向图表示某一区域的公交线路网,图中顶点代表一些区域中的重要场所,弧代表已有的公交线路,弧上的权表示该线路上的票价(或搭乘所需时间),试设计一个交通指南系统,指导前来咨询者以最低的票价或最少的时间从区域中的某一场所到达另一场所。
三、实验步骤
1. 定义结点结构,定义图结构。
2.存储图信息;
3. 定义求任意两点最短路径函数;
4. 写出主函数。
四、实现提示
typedef struct node
{ int no;
float wgt;
struct node *next;
}edgenode;
typedef struct
{ char vtx;
edgenode *link;
}vexnode;
typedef vexnode Graph[n];
void Floyd(Graph G, float A[n][n], int p[n][n])
{
int i, j, k;
for (i=0; i<n; i++)
for(j=0;j<n;j++)
{
A[i][j]=G[i][j];
P[i][j]=-1;
}
for (k=0; k<n; k++)
for (i=0; i<n; i++)
for (j=0; j<n; j++)
if(A[i][k] +A[k][j]<A[i][j])
{
P[i][j]=k;
A[i][j]=A[i][k]+A[k][j];
}
}
五、思考与提高(直接将答案写在小题后面)
1. 判断两点是否可达。
2.如何对程序进行修改,找一条人最少的公交线路?
3.练习图的拓扑排序
六、调试以下参考程序代码,并将运行效果截图
1.图的建立与遍历
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_VERTEX_NUM 20 //图的最大顶点数
#define MAXQSIZE 30 //队列的最大容量
enum BOOL {False,True};
typedefstructArcNode
{intadjvex; //该弧所指向的顶点的位置
structArcNode *nextarc; //指向下一条弧的指针
}ArcNode; //弧结点
typedefstruct
{ArcNode* AdjList[MAX_VERTEX_NUM]; //指向第一条依附该顶点的弧的指针
intvexnum,arcnum; //图的当前顶点和弧数intGraphKind; //图的种类,0---无向图,1---有向图
}Graph;
typedefstruct //队列结构
{intelem[MAXQSIZE]; //数据域
int front; //队头指针
int rear; //队尾指针
}SqQueue;
BOOL visited[MAX_VERTEX_NUM]; //全局变量——访问标志数组
void CreateGraph(Graph &); //生成图的邻接表
void DFSTraverse(Graph); //深度优先搜索遍历图
void DFS(Graph,int);
void BFSTraverse(Graph); //广度优先搜索遍历图
void Initial(SqQueue&); //初始化一个队列
BOOL QueueEmpty(SqQueue); //判断队列是否空
BOOL EnQueue(SqQueue&,int); //将一个元素入队列
BOOL DeQueue(SqQueue&,int&); //将一个元素出队列
intFirstAdjVex(Graph,int); //求图中某一顶点的第一个邻接顶点intNextAdjVex(Graph,int,int); //求某一顶点的下一个邻接顶点
void main()
{Graph G; //采用邻接表结构的图
char j='y';
printf("本程序将演示生成一个图,并对它进行遍历.\n");
printf("首先输入要生成的图的种类.\n");
printf("0---无向图, 1--有向图\n");
printf("之后输入图的顶点数和弧数。
\n格式:顶点数,弧数;例如:4,3\n"); printf("接着输入各边(弧尾,弧头).\n例如:\n1,2\n1,3\n2,4\n");
printf("程序会生成一个图,并对它进行深度和广度遍历.\n");
printf("深度遍历:1->2->4->3\n广度遍历:1->2->3->4\n");
while(j!='N'&&j!='n')
{printf("请输入要生成的图的种类(0/1):");
scanf("%d",&G.GraphKind); //输入图的种类
printf("请输入顶点数和弧数:");
scanf("%d,%d",&G.vexnum,&G.arcnum); //输入图的顶点数和弧数CreateGraph(G); //生成邻接表结构的图
DFSTraverse(G); //深度优先搜索遍历图
BFSTraverse(G); //广度优先搜索遍历图
printf("图遍历完毕,继续进行吗?(Y/N)");
scanf(" %c",&j);
}
}
voidCreateGraph(Graph &G)
{//构造邻接表结构的图G
int i;
intstart,end;
ArcNode *s;
for(i=1;i<=G.vexnum;i++) G.AdjList[i]=NULL; //初始化指针数组
for(i=1;i<=G.arcnum;i++)
{scanf("%d,%d",&start,&end); //输入弧的起点和终点
s=(ArcNode *)malloc(sizeof(ArcNode)); //生成一个弧结点
s->nextarc=G.AdjList[start]; //插入到邻接表中
s->adjvex=end;
G.AdjList[start]=s;
if(G.GraphKind==0) //若是无向图,再插入到终点的弧链中{s=(ArcNode *)malloc(sizeof(ArcNode));
s->nextarc=G.AdjList[end];
s->adjvex=start;
G.AdjList[end]=s;
}
}
}
voidDFSTraverse(Graph G)
{//深度优先遍历图G
int i;
printf("DFSTraverse:");
for(i=1;i<=G.vexnum;i++) visited[i]=False; //访问标志数组初始化for(i=1;i<=G.vexnum;i++)
if(!visited[i]) DFS(G,i); //对尚未访问的顶点调用DFS
printf("\b\b \n");
}
void DFS(Graph G,int i)
{//从第i个顶点出发递归地深度遍历图G
int w;
visited[i]=True; //访问第i个顶点
printf("%d->",i);
for(w=FirstAdjVex(G,i);w;w=NextAdjVex(G,i,w))
if(!visited[w]) DFS(G,w); //对尚未访问的邻接顶点w调用DFS }
voidBFSTraverse(Graph G)
{//按广度优先非递归的遍历图G,使用辅助队列Q和访问标志数组visited inti,u,w;
SqQueue Q;
printf("BFSTreverse:");
for(i=1;i<= G.vexnum;i++) visited[i]=False; //访问标志数组初始化Initial(Q); //初始化队列
for(i=1;i<=G.vexnum;i++)
if(!visited[i])
{visited[i]=True; //访问顶点i
printf("%d->",i);
EnQueue(Q,i); //将序号i入队列
while(!QueueEmpty(Q)) //若队列不空,继续
{DeQueue(Q,u); //将队头元素出队列并置为u
for(w=FirstAdjVex(G,u);w;w=NextAdjVex(G,u,w))
if(!visited[w]) //对u的尚未访问的邻接顶点w进行访问并入队列{visited[w]=True;
printf("%d->",w);
EnQueue(Q,w);
}
}
}
printf("\b\b \n");
}
intFirstAdjVex(Graph G,int v)
{//在图G中寻找第v个顶点的第一个邻接顶点
if(!G.AdjList[v]) return 0;
else return(G.AdjList[v]->adjvex);
}
intNextAdjVex(Graph G,intv,int u)
{//在图G中寻找第v个顶点的相对于u的下一个邻接顶点ArcNode *p;
p=G.AdjList[v];
while(p->adjvex!=u) p=p->nextarc; //在顶点v的弧链中找到顶点u if(p->nextarc==NULL) return 0; //若已是最后一个顶点,返回0 else return(p->nextarc->adjvex); //返回下一个邻接顶点的序号
}
void Initial(SqQueue&Q)
{//队列初始化
Q.front=Q.rear=0;
}
BOOL QueueEmpty(SqQueue Q)
{//判断队列是否已空,若空返回True,否则返回False
if(Q.front==Q.rear) return True;
else return False;
}
BOOL EnQueue(SqQueue&Q,intch)
{//入队列,成功返回True,失败返回False
if((Q.rear+1)%MAXQSIZE==Q.front) return False;
Q.elem[Q.rear]=ch;
Q.rear=(Q.rear+1)%MAXQSIZE;
return True;
}
BOOL DeQueue(SqQueue&Q,int&ch)
{//出队列,成功返回True,并用ch返回该元素值,失败返回False if(Q.front==Q.rear) return False;
ch=Q.elem[Q.front];
Q.front=(Q.front+1)%MAXQSIZE;
return True; //成功出队列,返回True
}
2.最短路径--迪杰斯特拉算法
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INFINITY 30000 //定义一个权值的最大值
#define MAX_VERTEX_NUM 20 //图的最大顶点数
enum BOOL {False,True};
typedefstruct
{int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵intvexnum,arcnum; //图的当前顶点和边数
}Graph;
void CreateGraph(Graph &); //生成图的邻接矩阵
voidShortestPath_DiJ(Graph,int,int[][MAX_VERTEX_NUM],int[]);
//用迪杰斯特拉算法求从某一源点到其余顶点的最短路径
voidPrint_ShortestPath(Graph,int,int[][MAX_VERTEX_NUM],int[]);
//显示最短路径
void main()
{Graph G; //采用邻接矩阵结构的图
char j='y';
int u;
int P[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //存放从源点到各顶点的最短路径
int D[MAX_VERTEX_NUM]; //存放从源点到各顶点的最短路径的距离
printf("本程序将演示利用迪杰斯特拉算法求\n从图的一点到其余顶点的最短路径.\n");
printf("首先输入图的顶点数和弧数.\n格式:顶点数,弧数;例如:5,7\n"); printf("然后输入各弧和权值.\n格式:弧尾,弧头,权值;例如:\n1,2,10\n1,3,18\n2,4,5\n3,2,5\n4,3,2\n4,5,2\n5,3,2\n");
printf("再输入从哪个顶点出发,例如:1\n");
printf("程序将会找出从1到其余顶点的最短路径.\n");
printf("10 1->2\n17 1->2->4->3\n15 1->2->4\n17 1->2->4->5\n");
while(j!='N'&&j!='n')
{CreateGraph(G); //生成邻接矩阵结构的图
printf("从哪个顶点出发:");
scanf("%d",&u); //输入迪杰斯特拉算法中的起始顶点
ShortestPath_DiJ(G,u,P,D); //利用迪杰斯特拉算法求最短路径
Print_ShortestPath(G,u,P,D); //显示最短路径
printf("最短路径演示完毕,继续进行吗?(Y/N)");
scanf(" %c",&j);
}
}
voidCreateGraph(Graph &G)
{//构造邻接矩阵结构的图G
inti,j;
intstart,end,weight;
printf("请输入图的顶点数和弧数(顶点数,弧数):");
scanf("%d,%d",&G.vexnum,&G.arcnum); //输入图的顶点数和边数
for(i=1;i<=G.vexnum;i++)
for(j=1;j<=G.vexnum;j++)
G.arcs[i][j]=INFINITY; //初始化邻接矩阵
printf("输入各弧和权值,格式:弧尾,弧头,权值\n");
for(i=1;i<=G.arcnum;i++)
{scanf("%d,%d,%d",&start,&end,&weight); //输入边的起点和终点及权值G.arcs[start][end]=weight;
}
}
voidShortestPath_DiJ(Graph G,int v0,int P[][MAX_VERTEX_NUM],int D[]) {//用迪杰斯特拉算法求有向网G的v0顶点到其余顶点v的最短路径P[v]及其带权路径长度D[v]
//若P[v][0]≠0,表明从源点出发存在一条到顶点v的最短路径,该路径存放在P[v]中
//final[v]为True则表明已经找到从v0到v的最短路径
inti,j,w,v;
int min;
BOOL final[MAX_VERTEX_NUM];
for(v=1;v<=G.vexnum;v++) //初始化
{final[v]=False; D[v]=G.arcs[v0][v];
for(i=0;i<=G.vexnum;i++) P[v][i]=0; //设空路径
//if(D[v]<INFINITY) P[v][0]=v0; //若从v0到v有直达路径
}
D[v0]=0; final[v0]=True; //初始时,v0属于S集
//开始主循环,每次求得v0到某个顶点v的最短路径,并加v到S集
for(i=1;i<=G.vexnum;i++) //寻找其余G.vexnum-1个顶点
{v=0;
min=INFINITY;
for(w=1;w<=G.vexnum;w++) //寻找当前离v0最近的顶点v
if((!final[w])&&(D[w]<min))
{v=w;min=D[w];}
if(!v) break; //若v=0表明所有与v0有通路的顶点均已找到了最短路径,退出主循环
final[v]=True; //将v加入S集
for(j=0;P[v][j]!=0;j++) ;
P[v][j]=v; //将路径P[v]延伸到顶点v
for(w=1;w<=G.vexnum;w++) //更新当前最短路径及距离
if(!final[w]&&(min+G.arcs[v][w]<D[w]))
{D[w]=min+G.arcs[v][w];
for(j=0;P[v][j]!=0;j++) P[w][j]=P[v][j];
}
}
}
voidPrint_ShortestPath(Graph G,int v0,int P[][MAX_VERTEX_NUM],int D[]) {//显示从顶点u到其余顶点的最短路径及距离
intv,j;
printf("The shortest path from Vertex %d to the other Vertex:\n");
for(v=1;v<=G.vexnum;v++)
{if(P[v][0]==0) continue; //表明顶点v0到顶点v没有通路
printf("%-4d",D[v]);
printf("%d->",v0);
for(j=0;P[v][j]!=0;j++)
printf("%d->",P[v][j]);
printf("\b\b \n");
}
}
3.最短路径--弗洛依德算法
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INFINITY 10000 //定义权值的最大值
#define MAX_NUM 20 //图的最大顶点数
enum BOOL {False,True};
typedefstruct
{int arcs[MAX_NUM][MAX_NUM]; //邻接矩阵
intvexnum,arcnum; //图的当前顶点和边数
}Graph;
void CreateGraph(Graph &); //生成图的邻接矩阵
void
ShortestPath_Floyd(Graph,BOOL[][MAX_NUM][MAX_NUM],int[][MAX_NU M]);
//用弗洛依德算法求每对顶点之间的最短路径
void
Print_ShortestPath(Graph,BOOL[][MAX_NUM][MAX_NUM],int[][MAX_NU M]);
//显示用弗洛依德算法所求得的最短路径
voidPrint_OnePath(int,int,int,BOOL[][MAX_NUM][MAX_NUM]);
//显示一对顶点之间的最短路径
void main()
{Graph G; //采用邻接矩阵结构的图
char j='y';
int u;
BOOL P[MAX_NUM][MAX_NUM][MAX_NUM]; //存放每对顶点的最短路径
int D[MAX_NUM][MAX_NUM]; //存放每对顶点的最短路径的距离printf("本程序演示弗洛依德算法求图的每一对顶点之间的最短路径。
\n"); printf("首先输入图的顶点和弧的数目。
\n例如:3,5\n");
printf("接着输入弧(i,j)和其权值。
\n例如:\n1,2,4\n2,1,6\n1,3,11\n3,1,3\n2,3,2\n");
printf("程序将会显示出每对顶点之间的最短路径值和所经过的路径:\n"); printf("4 1->2\n6 1->2->3\n5 2->3->1\n2 2->3\n3 3->1\n7 3->1->2\n");
while(j!='N'&&j!='n')
{CreateGraph(G); //生成邻接矩阵结构的图
ShortestPath_Floyd(G,P,D); //利用弗洛依德算法求最短路径
Print_ShortestPath(G,P,D); //显示每对顶点之间的最短路径
printf("继续执行吗?(Y/N)");
scanf(" %c",&j);
}
printf("程序运行结束,按任意键退出窗口!");
getch();
}
voidCreateGraph(Graph &G)
{//构造邻接矩阵结构的图G
inti,j;
intstart,end,weight;
printf("请输入顶点和弧的数目,格式:顶点数,弧数\n");
scanf("%d,%d",&G.vexnum,&G.arcnum); //输入图的顶点数和边数
for(i=1;i<=G.vexnum;i++)
for(j=1;j<=G.vexnum;j++)
G.arcs[i][j]=INFINITY; //初始化邻接矩阵
printf("请输入各条弧和其权值,格式:弧尾,弧头,权值:\n");
for(i=1;i<=G.arcnum;i++)
{scanf("%d,%d,%d",&start,&end,&weight); //输入边的起点和终点及权值G.arcs[start][end]=weight;
}
}
voidShortestPath_Floyd(Graph G,BOOL P[][MAX_NUM][MAX_NUM],int D[][MAX_NUM])
{//用弗洛依德算法求有向网G的每对顶点v和w之间的最短路径P[v][w] //及其带权路径长度D[v][w],
//若P[v][w][u]为True,表明u是从v到w当前求得最短路径上的顶点intu,v,w,i;
for(v=1;v<=G.vexnum;v++) //各对顶点之间的初始已知路径及距离
for(w=1;w<=G.vexnum;w++)
{D[v][w]=G.arcs[v][w];
for(u=1;u<=G.vexnum;u++) P[v][w][u]=False;
if(D[v][w]<INFINITY) //从v到w有直接路径
{P[v][w][v]=True;P[v][w][w]=True;}
}
for(u=1;u<=G.vexnum;u++)
for(v=1;v<=G.vexnum;v++)
for(w=1;w<=G.vexnum;w++)
if(D[v][u]+D[u][w]<D[v][w]&&v!=w) //从v经u到w的一条路径更短{D[v][w]=D[v][u]+D[u][w];
for(i=1;i<=G.vexnum;i++)
if(P[v][u][i]||P[u][w][i]) P[v][w][i]=True;
}
}
voidPrint_ShortestPath(Graph G,BOOL P[][MAX_NUM][MAX_NUM],int D[][MAX_NUM])
{//显示每对顶点之间的最短路径及距离
intv,w,j;
printf("最短路径:\n");
for(v=1;v<=G.vexnum;v++)
for(w=1;w<=G.vexnum;w++)
if(D[v][w]<INFINITY) //顶点v和w之间有通路
{printf("%-5d",D[v][w]); //从v到w的最短距离
Print_OnePath(v,w,G.vexnum,P); //显示从v到w的最短路径
printf("\n");
}
}
voidPrint_OnePath(intv,intw,intnum,BOOL P[][MAX_NUM][MAX_NUM]) {//显示从v到w的最短路径
int i;
for(i=1;i<=num;i++)
if(i!=v&&i!=w&&P[v][w][i]==True) break;
if(i>num) printf("%d->%d",v,w); //说明从v到w不需经过其它的顶点
else {Print_OnePath(v,i,num,P); //否则从v到w需经过顶点i,先显示从v到i的最短路径
if(i<10) printf("\b"); //控制显示格式,消除多余的"->"
elseprintf("\b\b");
Print_OnePath(i,w,num,P); //显示从i到w的最短路径
}
}。