目录
邻接表的相关知识
首先,让我们来了解一下邻接表的相关知识,熟悉下邻接表这种存储图的数据结构
https://blog.csdn.net/createprogram/article/details/100104235
简单来讲,就是将图中所有顶点存储到一个数组或单链表里,每个顶点本身又作为邻接表(边表)的头节点,边表用于存储当前顶点所有的邻接点,且按大小排序
题目分析:
函数接口定义:
void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) );
其中LGraph是邻接表存储的图,定义如下:
/* 邻接点的定义 */
typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode{
Vertex AdjV; /* 邻接点下标 */
PtrToAdjVNode Next; /* 指向下一个邻接点的指针 */
};
/* 顶点表头结点的定义 */
typedef struct Vnode{
PtrToAdjVNode FirstEdge; /* 边表头指针 */
} AdjList[MaxVertexNum]; /* AdjList是邻接表类型 */
/* 图结点的定义 */
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; /* 顶点数 */
int Ne; /* 边数 */
AdjList G; /* 邻接表 */
};
typedef PtrToGNode LGraph; /* 以邻接表方式存储的图类型 */
函数BFS应从第S个顶点出发对邻接表存储的图Graph进行广度优先搜索,遍历时用裁判定义的函数Visit访问每个顶点。当访问邻接点时,要求按邻接表顺序访问。题目保证S是图中的合法顶点。
裁判测试程序样例:
#include <stdio.h>
typedef enum {false, true} bool;
#define MaxVertexNum 10 /* 最大顶点数设为10 */
typedef int Vertex; /* 用顶点下标表示顶点,为整型 */
/* 邻接点的定义 */
typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode{
Vertex AdjV; /* 邻接点下标 */
PtrToAdjVNode Next; /* 指向下一个邻接点的指针 */
};
/* 顶点表头结点的定义 */
typedef struct Vnode{
PtrToAdjVNode FirstEdge; /* 边表头指针 */
} AdjList[MaxVertexNum]; /* AdjList是邻接表类型 */
/* 图结点的定义 */
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; /* 顶点数 */
int Ne; /* 边数 */
AdjList G; /* 邻接表 */
};
typedef PtrToGNode LGraph; /* 以邻接表方式存储的图类型 */
bool Visited[MaxVertexNum]; /* 顶点的访问标记 */
LGraph CreateGraph(); /* 创建图并且将Visited初始化为false;裁判实现,细节不表 */
void Visit( Vertex V )
{
printf(" %d", V);
}
void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) );
int main()
{
LGraph G;
Vertex S;
G = CreateGraph();
scanf("%d", &S);
printf("BFS from %d:", S);
BFS(G, S, Visit);
return 0;
}
/* 你的代码将被嵌在这里 */
乍一看,貌似没什么思路,这顶点这么多,对应边表也这么多,这该怎生是好?(滑稽)
别急,一步一步分析,把题目拆开来:
首先,要广度优先遍历,我先实现遍历如何?
第一步,遍历某个顶点的边表:
tmp = Graph->G[i].FirstEdge;//设置一个临时变量来存储当前顶点的第一个邻接点的指针
while (tmp)//判断是否到了某顶点边表末尾
{
Vertex pos = tmp->AdjV;
if (!Visited[pos])/*用来设置标记,判断当前节点有没有输出过*/
{
Visit(pos);
Visited[pos] = true;
}
tmp = tmp->Next;//依次遍历当前顶点的邻接点
}
第二步,遍历所有顶点的边表(这里用队列来实现)
int queue[11]; //定义一个数组,存储入队过的顶点
int l = 0, r = 0;//用来实现队列,即先进先出
while (l != r) //队列不为空
{
tmp = Graph->G[queue[l++]].FirstEdge;//当前顶点出队,边表头结点是当前顶点的边表头结点
while (tmp)//判断是否到了某顶点边表末尾
{
Vertex pos = tmp->AdjV;
if (!Visited[pos])
{
Visit(pos);
Visited[pos] = true;
queue[r++] = pos;//将未入队的邻接点入队
}
tmp = tmp->Next;//依次遍历当前顶点的邻接点
}
}
第三步,输出起始顶点的值并设置为已经输出过
int queue[11]; //定义一个数组,存储入队过的顶点
int l = 0, r = 0;//用来实现队列,即先进先出
queue[r++] = S;
Visit(S);
Visited[S] = true;
PtrToAdjVNode tmp;
/*两层循环作用:当前顶点的边表结点即邻接点全部遍历完成后,才遍历下一个顶点*/
while (l != r) //队列不为空
{
tmp = Graph->G[queue[l++]].FirstEdge;//当前顶点出队,边表头结点是当前顶点的边表头结点
while (tmp)//判断是否到了某顶点边表末尾
{
Vertex pos = tmp->AdjV;
if (!Visited[pos])
{
Visit(pos);
Visited[pos] = true;
queue[r++] = pos;//将未入队的邻接点入队
}
tmp = tmp->Next;//依次遍历当前顶点的邻接点
}
}
到这里,第三步所得代码即为所需的BFS函数代码
更加详细的实现: