您的位置:首页 > 其它

第十二周项目4-利用遍历思想求解图问题(2-广度优先遍历)

2016-11-20 18:55 489 查看
问题及代码:

/*

copyright (t) 2016,烟台大学计算机学院

*All rights reserved.

*文件名称:1.cpp

*作者:常锐

*完成日期:2016年11月18日

*版本号:v1.0

*问题描述:假设图G采用邻接表存储,分别设计实现以下要求的算法,要求用区别于示例中的图进行多次测试,通过观察输出值,掌握相关问题的处理方法。
(6)求不带权连通图G中从顶点u到顶点v的一条最短路径。
  (7)求不带权连通图G中,距离顶点v最远的顶点k

*输入描述:无

*程序输出:测试结果

*/代码及运行结果:
(算法库准备工作:)

graph.h:

#include <stdio.h>
#define MAXV 100 //定义最大顶点数100
#define limitless 9999 //处理“无穷大”
typedef int InfoType; //定义顶点与边的相关信息
typedef int Vertex;

typedef struct //定义顶点类型
{
int no; //顶点编号
InfoType info; //顶点其他信息
} VertexType;
typedef struct //定义图邻接矩阵类型
{
int edges[MAXV][MAXV]; //邻接矩阵边数组
int n; //顶点数
int e; //边数
VertexType vexs[MAXV]; //存放顶点信息
} MGraph;

typedef struct ANode //定义边节点类型
{
int adjvex; //该边终点编号
struct ANode *nextarc; //指向下一条边的指针
InfoType info; //该边相关信息
} ArcNode;
typedef struct VNode //定义邻接表头节点类型
{
Vertex data; //顶点信息
ArcNode *firstarc; //指向第一条边的指针
} VNode;
typedef VNode AdjList[MAXV]; //AdjList: 邻接表类型
typedef struct //定义图邻接表类型
{
AdjList adjlist; //邻接表
int n; //图中顶点数
int e; //图中边数
} ALGraph;

void ArrayToMat(int *Arr, int n, MGraph &g); //用普通数组构造图的邻接矩阵
void ArrayToList(int *Arr, int n, ALGraph *&G); //用普通数组构造图的邻接表
void MatToList(MGraph g,ALGraph *&G); //将邻接矩阵g转换成邻接表G
void ListToMat(ALGraph *G,MGraph &g); //将邻接表G转换成邻接矩阵g
void DispMat(MGraph g); //输出邻接矩阵g
void DispAdj(ALGraph *G); //输出邻接表G


graph.cpp:
#include <malloc.h>
#include "graph.h"
//几点说明:
//功能:由一个反映图中顶点邻接关系的二维数组,构造出用邻接矩阵存储的图
//参数:Arr - 数组名,由于形式参数为二维数组时必须给出每行的元素个数,在此将参数Arr声明为一维数组名(指向int的指针)
// n - 矩阵的阶数
// g - 要构造出来的邻接矩阵数据结构
void ArrayToMat(int *Arr, int n, MGraph &g) //用普通数组构造图的邻接矩阵
{
int i,j;
int edgenum=0; //边数初始化为0
g.n=n;
for(i=0;i<g.n;i++)
{
for(j=0;j<g.n;j++)
{
g.edges[i][j]=Arr[i*n+j]; //计算存储位置
if(g.edges[i][j]!=0 && g.edges[i][j]!=limitless)
edgenum++;
}
}
g.e=edgenum;
}
void ArrayToList(int *Arr, int n, ALGraph *&G) //用普通数组构造图的邻接表
{
int i,j;
int edgenum=0; //边数初始化为0
ArcNode *p; //后续操作中创建的新节点
G=(ALGraph *)malloc(sizeof(ALGraph));
G->n=n;
for(i=0;i<n;i++) //邻接表所有头节点指针域置初值
G->adjlist[i].firstarc=NULL;
for(i=0;i<n;i++) //遍历邻接矩阵中的每个元素
{
for(j=n-1;j>=0;j--)
{
if(Arr[i*n+j]!=0)
{
p=(ArcNode *)malloc(sizeof(ArcNode)); //创建节点*p
p->adjvex=j;
p->info=Arr[i*n+j];
p->nextarc=G->adjlist[i].firstarc; //头插法插入*p
G->adjlist[i].firstarc=p; //指向第一条边的指针指向*p
}
}
}
G->e=edgenum;
}
void MatToList(MGraph g,ALGraph *&G) //将邻接矩阵g转换成邻接表G
{
int i,j;
ArcNode *p;
G=(ALGraph *)malloc(sizeof(ALGraph));
for(i=0;i<g.n;i++) //给邻接表所有头节点的指针域置初值
G->adjlist[i].firstarc=NULL;
for(i=0;i<g.n;i++) //遍历邻接矩阵中的每个元素
{
for(j=g.n-1;j>=0;j--)
{
if(g.edges[i][j]!=0)
{
p=(ArcNode *)malloc(sizeof(ArcNode)); //创建一个节点*p
p->adjvex=j; //终点编号赋值
p->nextarc=G->adjlist[i].firstarc; //头插法插入节点*p
G->adjlist[i].firstarc=p; //连接
}
}
}
G->n=g.n;
G->e=g.e;
}
void ListToMat(ALGraph *G,MGraph &g) //将邻接表G转换成邻接矩阵g
{
//前提要求:g的实参调用前已经初始化为全0
int i;
ArcNode *p;
for(i=0;i<G->n;i++)
{
p=G->adjlist[i].firstarc; //*p指向每个顶点的第一条边
while(p!=NULL) //依次遍历
{
g.edges[i][p->adjvex]=1; //p不为空指针时对应矩阵元素赋值1
p=p->nextarc; //*p指向下一条边
}
}
g.n=G->n;
g.e=G->e;
}
void DispMat(MGraph g) //输出邻接矩阵g
{
int i,j;
for(i=0;i<g.n;i++)
{
for(j=0;j<g.n;j++)
if(g.edges[i][j]==limitless)
printf("%3s","∞");
else
printf("%3d",g.edges[i][j]);
printf("\n");
}
}
void DispAdj(ALGraph *G) //输出邻接表G
{
int i;
ArcNode *p;
for (i=0; i<G->n; i++)
{
p=G->adjlist[i].firstarc;
printf("%3d: ",i);
while (p!=NULL)
{
printf("-->%d/%d ",p->adjvex,p->info);
p=p->nextarc;
}
printf("\n");
}
}

(6)求不带权连通图G中从顶点u到顶点v的一条最短路径:main.cpp:
#include <stdio.h>
#include "graph.h"
typedef struct //定义非环形队列类型
{
int data; //顶点编号
int parent; //前一顶点位置
} Queue;
void ShortPath(ALGraph *G,int u,int v) //输出从顶点u到顶点v的最短逆路径
{
ArcNode *p;
int w,i;
Queue qu[MAXV]; //非环形队列qu
int front=-1,rear=-1; //队列头尾”伪指针“,初始化为-1
int visited[MAXV];
for(i=0;i<G->n;i++)
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("%2d ",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的下一个邻接点
}
}
}

int main()
{
ALGraph *G;
int A[9][9]=
{
{0,1,1,0,0,0,0,0,0},
{0,0,0,1,1,0,0,0,0},
{0,0,0,0,1,1,0,0,0},
{0,0,0,0,0,0,1,0,0},
{0,0,0,0,0,1,1,0,0},
{0,0,0,0,0,0,0,1,0},
{0,0,0,0,0,0,0,1,1},
{0,0,0,0,0,0,0,0,1},
{0,0,0,0,0,0,0,0,0}
};
ArrayToList(A[0], 9, G);
ShortPath(G,0,7);
return 0;
}
测试用图:



运行结果:



(7)求不带权连通图G中,距离顶点v最远的顶点k:main.cpp:

#include <stdio.h>
#include "graph.h"
int Maxdist(ALGraph *G,int v)
{
ArcNode *p;
int i,j,k;
int Qu[MAXV]; //环形队列
int visited[MAXV]; //访问标记数组
int front=0,rear=0; //队列的头、尾指针
for (i=0; i<G->n; i++) //初始化访问标志数组
visited[i]=0;
rear++;
Qu[rear]=v; //顶点v进队
visited[v]=1; //标记v已访问
while (rear!=front)
{
front=(front+1)%MAXV;
k=Qu[front]; //顶点k出队
p=G->adjlist[k].firstarc; //找第一个邻接点
while (p!=NULL) //所有未访问过的相邻点进队
{
j=p->adjvex; //邻接点为顶点j
if (visited[j]==0) //若j未访问过
{
visited[j]=1;
rear=(rear+1)%MAXV;
Qu[rear]=j; //进队
}
p=p->nextarc; //找下一个邻接点
}
}
return k;
}

int main()
{
ALGraph *G;
int A[9][9]=
{
{0,1,1,0,0,0,0,0,0},
{0,0,0,1,1,0,0,0,0},
{0,0,0,0,1,1,0,0,0},
{0,0,0,0,0,0,1,0,0},
{0,0,0,0,0,1,1,0,0},
{0,0,0,0,0,0,0,1,0},
{0,0,0,0,0,0,0,1,1},
{0,0,0,0,0,0,0,0,1},
{0,0,0,0,0,0,0,0,0}
};
ArrayToList(A[0], 9, G);
printf("离顶点0最远的顶点:%d",Maxdist(G,0));
return 0;
}

测试用图:



运行结果:



知识点总结:

        广度优先遍历算法的应用

心得体会:

        结合求最短路径的问题,可见图遍历算法的大用;同时,也为后续最短路径等内容的进一步学习做好了铺垫。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: