图的广度优先查找(BFS: Breadth -FirstSearch)
(1)问题分析
BFS的策略是尽可能广泛地搜索图。它首先访问所有和初始顶点邻接的顶点,然后访问距离它两条边的所有未访问的顶点。以此类推,直到所有与初始顶点同在一个连通分量中的顶点都访问过了为止。若仍存在未被访问的顶点,该算法从图的其他连通分量中的任意顶点重新开始。
(2)解题思路
BFS队列
将遍历的初始顶点作为队列队头顶点,并标记为已访问。在每次迭代时, 该算法找出所有和队头顶点邻接的未访问顶点,将其标记为已访问,并把它们入队,然后从队列中移去队头顶点。
BFS森林
完全类似DFS森林的定义,只不过在DFS森林中,指向已访问顶点的边称为回边,而在BFS森林中,这种边称为交叉边。
代码实现:
#include <iostream>
#include <cstring>
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)<(b)?(a):(b)
using namespace std;
int map[30][30];
int tof[30];
char arr[100];
int maxn = -1, minn = 30;
// 搜索arr数组从beg到end范围内的顶点
void BFS(int beg, int end)
{
int i, j, k = end + 1;
int t;
int count = 0;
// 将搜索到的点放入arr数组中
arr[end] = '\n';
for (i = beg; i < end; ++i)
{
if (arr[i] == '|') continue;
t = arr[i] - 'a';
for (j = minn; j <= maxn; ++j)
{
if (map[t][j] && tof[j])
{
arr[k++] = j + 'a';
tof[j] = 0;
count++;
}
}
k++;
}
k--;
arr[k] = '\n';
// 如果没有点可以继续搜索,则退回上一顶点
if (!count)
{
arr[k] = '\0';
return ;
}
BFS(end + 1, k);
}
int main()
{
int n, m;
char a, b;
int c, d;
int i, j;
// 输入
memset(map, 0, sizeof(map));
memset(tof, 0, sizeof(tof));
printf("请输入顶点个数n以及边数m,格式为<n m>:");
cin >> n >> m;
printf("请分别输入%d条边所对应的两个顶点,格式为<a b>:\n",m);
for (i = 0; i < m; ++i)
{
cin >> a >> b;
c = a - 'a';
d = b - 'a';
tof[c] = tof[d] = 1;
// 构建邻接矩阵,求出最小点和最大点
map[c][d] = map[d][c] = 1;
maxn = MAX(maxn, c);
maxn = MAX(maxn, d);
minn = MIN(minn, c);
minn = MIN(minn, d);
}
// 进行广度优先搜索
for (i = minn; i <= maxn; ++i)
{
if (tof[i])
{
// 初始化arr数组
memset(arr, '|', sizeof(arr));
arr[0] = i + 'a';
arr[1] = '\n';
tof[i] = 0;
BFS(0, 1);
// 输出
printf("广度优先生成树(与每个顶点连接的点在下一行用‘|’隔开)\n");
for (j = 0; arr[j] != '\0'; ++j)
{
if (arr[j] == '\n') printf("\n");
else printf("%c ", arr[j]);
}
printf("\n");
}
}
printf("遍历结束!\n");
}
画如下所示的图:
运行结果:
生成树为: