内容:
采用邻接矩阵形式存储图,进行图的深度优先搜索并输出结果。
步骤:
- 算法分析
本题需要利用邻接矩阵的形式存储图,并对图进行深度优先搜索并输出结果。大体上可以分为两个部分,一是采用邻接矩阵的方式存储图,二是对图进行深度优先搜索并输出。
对于第一部分,图是一种结构复杂的数据结构,图的常用存储结构有四种,分别为邻接矩阵、邻接表、十字链表和邻接多重表。其中相较于十字链表和邻接多重表来说,邻接矩阵和邻接表较为简单,也更好理解。此题采用邻接矩阵形式存储图,存储时分为两个部分,顶点的信息和顶点之间的关系,分为两部分来存储:用一维数组来存储顶点信息,用二维数组来存储弧的信息。
图的邻接存储结构结构如下:
typedef struct
{
int vexs[Max];//图中顶点的最大个数
int edges[Max][Max];//整数中允许的最大值
int n,e;//定义图中的顶点数和弧数
}Graph;
//建立图以及图的初始化
void create(Graph &G)
{
for(int i=0;i<Max;i++)
for(int j=0;j<Max;j++)
(G.edges)[i][j]=0;
G.n=0;
G.e=0;
}
//定义图中的顶点
void vertex(Graph &G,int v)
{
(G.n)++;
int a=G.n;
(G.vexs)[a-1]=v;
for(int i=0;i<G.n;i++)
{
G.edges[i][a-1]=0;
G.edges[a-1][i]=0;
}
}
//定义图中的弧
void arc(Graph &G,int v,int w)
{
G.e++;
int m=0,n=0;
for(int i=0;i<G.n;i++)
{
if((G.vexs)[i]==v)
m=i;
if((G.vexs)[i]==w)
n=i;
}
(G.edges)[m][n]=1;
(G.edges)[n][m]=1;
}
其次是深度优先遍历并输出。图的深度优先遍历类似于树的先遍根历,是树先根遍历的推广,深度优先遍历的过程如下:
- 将图中所有顶点做“未访问过”标记;
- 任选图中一个未被访问过的顶点v作为遍历起点;
- 访问v结点,然后深度优先访问v的第一个未被访问的邻接点w1;
- 再从w1出发深度优先访问w1的第一个未被访问的邻接点w2……如此下去,直到到达一个所有邻接点都被访问过的顶点为止;
- 然后依次退回,查找前一结点wi-1是否还有未被访问过的邻接点,如果存在尚未被访问过的邻接点,则访问此邻接点,并从该结点出发按深度优先的规则访问。如果结点wi-1不存在尚未被访问过的邻接点,则再后退一步,直到找到有尚未被访问过的邻接点的顶点;
- 重复上述过程,直到图中所有与v有路径相连的顶点都被访问过;
- 若此时图中还有顶点未被访问,则转(2);否则,遍历结束。
该算法可采用递归的方式实现,即找到结点v,访问v的第一个邻接点w,如果邻接点w存在且为被访问,则从w出发深度优先遍历图,否则,结束,找到顶点v关于w的下一个邻接点,继续判断,直至结束。
2.概要设计
使用C语言,其中设置了以下函数
程序运行流程图如下:
3、测试(设计测试用例或测试代码的设计与实现,测试结果截屏))
设计测试用例如下图:
该测试样例中共有六个顶点为{1,2,3,4,5,6},共有10条弧,分别为{(1,5),(2,3),(2,4),(2,6),(3,1),(3,2),(3,4),(3,5),(5,1),(5,4)}.
该测试案例所表示的图如下:
该程序运行结果为如下:
源码如下:
#include <stdio.h>
#define Max 10//图中顶点的最大个数
#define INFINITY 100//整数中允许的最大值
//定义图的邻接矩阵存储方式
typedef struct
{
int vexs[Max];//图中顶点的最大个数
int edges[Max][Max];//整数中允许的最大值
int n,e;//定义图中的顶点数和弧数
}Graph;
//建立图以及图的初始化
void create(Graph &G)
{
for(int i=0;i<Max;i++)
for(int j=0;j<Max;j++)
(G.edges)[i][j]=0;
G.n=0;
G.e=0;
}
//定义图中的顶点
void vertex(Graph &G,int v)
{
(G.n)++;
int a=G.n;
(G.vexs)[a-1]=v;
for(int i=0;i<G.n;i++)
{
G.edges[i][a-1]=0;
G.edges[a-1][i]=0;
}
}
//定义图中的弧
void arc(Graph &G,int v,int w)
{
G.e++;
int m=0,n=0;
for(int i=0;i<G.n;i++)
{
if((G.vexs)[i]==v)
m=i;
if((G.vexs)[i]==w)
n=i;
}
(G.edges)[m][n]=1;
(G.edges)[n][m]=1;
}
//打印输出邻接矩阵
void Print_graph(Graph G)
{
for (int i=0;i<G.n;i++)
printf(" %d",(G.vexs)[i]);
printf("\n");
for (int i=0;i<G.n;i++)
{
printf("%d",(G.vexs)[i]);
for(int j=0;j<G.n;j++)
printf("%d ",(G.edges)[i][j]);
printf("\n");
}
}
//图的深度优先搜索
bool visited[Max] ; //访问标记数组
int FirstAdjVertex(Graph G, int v){
int i;
for(i=0;i<G.n;++i){
if(G.edges[v][i]==1&&visited[i]==false)
return i;
}
return -1;
}
int NextAdjVertex(Graph G,int v,int w){
int i;
for(i=w;i<G.n;++i){
if(G.edges[v][i]==1&&visited[i]==false)
return i;
}
return -1;
}
void DepthFirstSearch(Graph G,int v) {//深度遍历v所在的连通子图
int w;
printf("%d ",G.vexs[v]);
visited[v]=true;//置访问标识数组相应分量值
/*寻找第一个邻接点,若邻接点存在,则判断是否被访问过
如果未被访问,则递归调用DepthFirstSearch,否则寻找下一个邻接点
*/
for(w=FirstAdjVertex(G,v);w>=0;w=NextAdjVertex(G,v,w))
if (!visited [w]){//调用深度遍历算法
DepthFirstSearch(G,w);
}
}
//图的深度优先搜索算法
void TravelGraph(Graph G){
//初始化访问标识数组
for (int v=0;v<G.n;++v)
visited[v]=false;
for (int v=0;v<G.n;++v)
if (!visited[v])
DepthFirstSearch(G,v);
}
int main()
{
Graph G;
int a=-1;
int v,i,j=1;
create(G);
printf("输入所有结点(-1结束输入):\n");
printf("输入第1个结点:");
scanf("%d",&v);
int p=2;
while(v!=-1){
vertex(G,v);
printf("输入第%d个结点:",p);
scanf("%d",&v);
p++;
}
printf("\n输入弧两端的结点(-1 -1结束输入):\n");
printf("输入第1条弧:");
scanf("%d %d",&i,&j);
int k=2;
while(i!=-1&&j!=-1){
arc(G,i,j);
printf("输入第%d条弧:",k);
scanf("%d %d",&i,&j);
k++;
}
printf("\n邻接矩阵:\n");
Print_graph(G);
printf("\n深度优先搜索结果:\n");
TravelGraph(G);
printf("\n");
}