广度优先搜索(BFS,Breadth-First Search)是一种用于遍历或搜索树或图的算法。它从根节点(或起始节点)开始,逐层地对节点进行访问,先访问距离起始节点最近的所有节点,然后再依次访问距离更远的节点。下面将从算法原理、代码实现二个方面详细介绍 BFS 算法。
目录
前言
函数名 | 功能描述 | 注意事项 |
---|---|---|
queue<T> q; | 构造一个存储类型为 T 的空队列 | - |
q.push(item) | 将元素 item 添加到队列的尾部 | - |
q.pop() | 移除队列头部的元素,但不返回该元素 | 调用前需确保队列非空,否则导致未定义行为 |
q.front() | 返回队列头部元素的引用,不移除该元素 | 调用前需确保队列非空,否则导致未定义行为 |
q.back() | 返回队列尾部元素的引用,不移除该元素 | 调用前需确保队列非空,否则导致未定义行为 |
q.empty() | 检查队列是否为空,为空返回 true ,否则返回 false | - |
q.size() | 返回队列中元素的数量 | - |
#include <iostream>
#include <queue>
int main() {
// 1. 构造函数:创建一个存储 int 类型元素的空队列
std::queue<int> myQueue;
// 检查队列是否为空
if (myQueue.empty()) {
std::cout << "队列初始为空,大小为: " << myQueue.size() << std::endl;
}
// 2. push():将元素添加到队列尾部
myQueue.push(10);
myQueue.push(20);
myQueue.push(30);
std::cout << "添加元素后,队列大小为: " << myQueue.size() << std::endl;
// 3. front():获取队列头部元素
if (!myQueue.empty()) {
int frontElement = myQueue.front();
std::cout << "队列头部元素是: " << frontElement << std::endl;
}
// 4. back():获取队列尾部元素
if (!myQueue.empty()) {
int backElement = myQueue.back();
std::cout << "队列尾部元素是: " << backElement << std::endl;
}
// 5. pop():移除队列头部元素
if (!myQueue.empty()) {
myQueue.pop();
std::cout << "移除头部元素后,队列大小为: " << myQueue.size() << std::endl;
}
// 再次获取队列头部元素
if (!myQueue.empty()) {
int newFrontElement = myQueue.front();
std::cout << "移除后新的队列头部元素是: " << newFrontElement << std::endl;
}
return 0;
}
算法原理
BFS 算法使用队列(Queue)来实现,具体步骤如下:
初始化:将起始节点放入队列中,并标记该节点为已访问。
循环处理:从队列中取出一个节点。访问该节点。将该节点的所有未访问过的邻接节点加入队列,并标记它们为已访问。
终止条件:当队列为空时,算法结束。
代码实现
邻近矩阵
上图是部分代码,完整代码如下
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
// 图的 BFS 遍历函数,使用邻接矩阵表示图
void bfs(const vector<vector<int>>& graph, int start) {
int n = graph.size();
vector<bool> visited(n, false); // 标记节点是否已访问
queue<int> q; // 用于 BFS 的队列
// 将起始节点加入队列并标记为已访问
q.push(start);
visited[start] = true;
while (!q.empty()) {
// 取出队首节点
int current = q.front();
q.pop();
// 访问当前节点
cout << current << " ";
// 遍历当前节点的所有邻接节点
for (int i = 0; i < n; ++i) {
if (graph[current][i] == 1 && !visited[i]) {
// 如果存在边且邻接节点未被访问
q.push(i);
visited[i] = true;
}
}
}
}
int main() {
// 用邻接矩阵表示一个图
vector<vector<int>> graph = {
{0, 1, 1, 0, 0}, // 节点 0 的邻接情况
{1, 0, 0, 1, 0}, // 节点 1 的邻接情况
{1, 0, 0, 1, 0}, // 节点 2 的邻接情况
{0, 1, 1, 0, 1}, // 节点 3 的邻接情况
{0, 0, 0, 1, 0}
};
// 从节点 0 开始进行 BFS 遍历
cout << "BFS 遍历结果: ";
bfs(graph, 0);
cout << endl;
return 0;
}
图的遍历
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
// 图的 BFS 遍历函数
void bfs(const vector<vector<int>>& graph, int start) {
int n = graph.size();
vector<bool> visited(n, false); // 标记节点是否已访问
queue<int> q; // 用于 BFS 的队列
// 将起始节点加入队列并标记为已访问
q.push(start);
visited[start] = true;
while (!q.empty()) {
// 取出队首节点
int current = q.front();
q.pop();
// 访问当前节点
cout << current << " ";
// 遍历当前节点的所有邻接节点
for (int neighbor : graph[current]) {
if (!visited[neighbor]) {
// 将未访问过的邻接节点加入队列并标记为已访问
q.push(neighbor);
visited[neighbor] = true;
}
}
}
}
int main() {
// 用邻接表表示一个图
vector<vector<int>> graph = {
{1, 2}, // 节点 0 的邻接节点是 1 和 2
{0, 3}, // 节点 1 的邻接节点是 0 和 3
{0, 3}, // 节点 2 的邻接节点是 0 和 3
{1, 2} // 节点 3 的邻接节点是 1 和 2
};
// 从节点 0 开始进行 BFS 遍历
cout << "BFS 遍历结果: ";
bfs(graph, 0);
cout << endl;
return 0;
}
迷宫例题
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
// 定义四个方向的偏移量
const int directions[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
// BFS函数
int bfs(vector<vector<int>>& maze, pair<int, int> start, pair<int, int> end) {
int rows = maze.size();
int cols = maze[0].size();
vector<vector<bool>> visited(rows, vector<bool>(cols, false));//记录是否访问过当前节点
queue<pair<pair<int, int>, int>> q; // 队列中存储坐标和步数 类似(1,0),1;(2,0),2
q.push({start, 0});
visited[start.first][start.second] = true;//访问过当前节点,由false变为true
while (!q.empty()) {
auto [current, steps] = q.front();//回到列表首元素
q.pop();//先进先出,首元素出
if (current == end) {
return steps;
}
for (int i = 0; i < 4; ++i) {
int newX = current.first + directions[i][0];
int newY = current.second + directions[i][1];
if (newX >= 0 && newX < rows && newY >= 0 && newY < cols &&
!visited[newX][newY] && maze[newX][newY] == 0) {
visited[newX][newY] = true;
q.push({{newX, newY}, steps + 1});
}
}
}
return -1; // 如果无法到达终点返回 -1
}
int main() {
// 定义迷宫,0表示通路,1表示障碍物
vector<vector<int>> maze = {
{0, 0, 1, 0},
{0, 0, 0, 0},
{0, 0, 1, 0},
{0, 1, 0, 0}.
{0, 0, 0, 1}
};
// 定义起点和终点坐标
pair<int, int> start = {0, 0};
pair<int, int> end = {2, 3};
int result = bfs(maze, start, end);
if (result != -1) {
cout << "最短路径步数: " << result << endl;
} else {
cout << "无法到达终点" << endl;
}
return 0;
}