广度优先搜索(Breadth-First Search,简称BFS)是一种用于图和树等数据结构的遍历算法。它从根节点(或起始节点)开始,首先访问根节点,然后逐层遍历子节点,直到遍历完所有节点为止。BFS通常使用队列数据结构来实现。
树的广度优先遍历
树的广度优先遍历的写法模式相对固定:
1.使用队列;
2.在队列非空的时候,动态取出队首元素;
3.取出队首元素的时候,把队首元素相邻的结点(非空)加入队列。
// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
std::vector<std::vector<int>> levelOrder(TreeNode* root) {
std::vector<std::vector<int>> res;
if (root == nullptr) {
return res;
}
std::queue<TreeNode*> queue;
queue.push(root);
while (!queue.empty()) {
int currentSize = queue.size();
std::vector<int> currentLevel;
for (int i = 0; i < currentSize; i++) {
TreeNode* front = queue.front();
queue.pop();
currentLevel.push_back(front->val);
if (front->left != nullptr) {
queue.push(front->left);
}
if (front->right != nullptr) {
queue.push(front->right);
}
}
res.push_back(currentLevel);
}
return res;
}
int main() {
// 创建一个示例二叉树
TreeNode* root = new TreeNode(3);
root->left = new TreeNode(9);
root->right = new TreeNode(20);
root->right->left = new TreeNode(15);
root->right->right = new TreeNode(7);
std::vector<std::vector<int>> result = levelOrder(root);
// 打印结果
for (const std::vector<int>& level : result) {
for (int val : level) {
std::cout << val << " ";
}
std::cout << std::endl;
}
// 释放内存(在实际应用中要注意内存管理)
delete root->right->right;
delete root->right->left;
delete root->right;
delete root->left;
delete root;
return 0;
}
邻接矩阵广度优先
class Graph {
public:
Graph(int vertices); // 构造函数
void addEdge(int v, int w); // 添加边
void BFS(int start); // 广度优先遍历
private:
int vertices; // 图的顶点数
bool** adjMatrix; // 邻接矩阵
};
// 构造函数
Graph::Graph(int vertices) {
this->vertices = vertices;
adjMatrix = new bool* [vertices];
for (int i = 0; i < vertices; i++) {
adjMatrix[i] = new bool[vertices];
for (int j = 0; j < vertices; j++) {
adjMatrix[i][j] = false; // 初始化矩阵为false
}
}
}
// 添加边
void Graph::addEdge(int v, int w) {
adjMatrix[v][w] = true;
adjMatrix[w][v] = true; // 无向图需要双向引用
}
// 广度优先遍历
void Graph::BFS(int start) {
bool* visited = new bool[vertices];
for (int i = 0; i < vertices; i++) {
visited[i] = false; // 初始化为未访问状态
}
queue<int> q;
visited[start] = true;
q.push(start);
while (!q.empty()) {
int current = q.front();
cout << current << " ";
q.pop();
for (int i = 0; i < vertices; i++) {
if (adjMatrix[current][i] && !visited[i]) {
visited[i] = true;
q.push(i);
}
}
}
delete[] visited;
}
int main() {
int vertices = 6;
Graph g(vertices);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 3);
g.addEdge(1, 4);
g.addEdge(2, 4);
g.addEdge(3, 5);
cout << "Breadth-First Traversal starting from node 0:" << endl;
g.BFS(0);
return 0;
}
邻接表广度优先
class Graph {
public:
Graph(int vertices); // 构造函数
void addEdge(int v, int w); // 添加边
void BFS(int start); // 广度优先遍历
private:
int vertices; // 图的顶点数
vector<vector<int>> adj; // 邻接表表示的图
};
// 构造函数
Graph::Graph(int vertices) {
this->vertices = vertices;
adj.resize(vertices);
}
// 添加边
void Graph::addEdge(int v, int w) {
adj[v].push_back(w);
}
// 广度优先遍历
void Graph::BFS(int start) {
vector<bool> visited(vertices, false); // 记录节点是否已访问
queue<int> q; // 队列用于存储待访问的节点
// 将起始节点放入队列并标记为已访问
q.push(start);
visited[start] = true;
while (!q.empty()) {
int current = q.front(); // 获取队首节点
q.pop();
cout << current << " "; // 访问节点
// 遍历当前节点的邻居节点
for (int neighbor : adj[current]) {
if (!visited[neighbor]) {
q.push(neighbor); // 将未访问的邻居节点放入队列
visited[neighbor] = true; // 标记为已访问
}
}
}
}
int main() {
int vertices = 7; // 图的顶点数
Graph g(vertices);
// 添加边
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 3);
g.addEdge(1, 4);
g.addEdge(2, 5);
g.addEdge(3, 6);
cout << "Breadth-First Traversal starting from node 0:" << endl;
g.BFS(0); // 从节点0开始的广度优先遍历
return 0;
}
双向广度优先遍历
应用于这样的特殊场景:无向图(无向图可以看成双向有向图),有明确的搜索 终点(目标)。
双向广度优先遍历,分别从起始状态和目标状态开始,以交替的方式扩展每一层,当两边搜索的状态列表有交集的时候,表示搜索过程相遇,搜索终止。双向 BFS 等价于单向 BFS,但是避免了单向 BFS 在层数很深的时候状态结点的大规模扩散。
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
using namespace std;
class Graph {
public:
Graph(int vertices);
void addEdge(int u, int v);
vector<int> bidirectionalBFS(int start, int end);
private:
int vertices;
unordered_map<int, vector<int>> adjacencyList;
};
Graph::Graph(int vertices) {
this->vertices = vertices;
}
void Graph::addEdge(int u, int v) {
adjacencyList[u].push_back(v);
adjacencyList[v].push_back(u); // 无向图需要双向连接
}
vector<int> Graph::bidirectionalBFS(int start, int end) {
vector<int> result;
if (start == end) {
result.push_back(start);
return result;
}
// 用于从起点和终点开始的广度优先搜索
queue<int> forwardQueue, backwardQueue;
// 记录从起点和终点分别访问过的节点
vector<bool> forwardVisited(vertices, false);
vector<bool> backwardVisited(vertices, false);
// 记录从起点和终点分别到达当前节点的路径
unordered_map<int, int> forwardParent, backwardParent;
forwardQueue.push(start);
backwardQueue.push(end);
forwardVisited[start] = true;
backwardVisited[end] = true;
while (!forwardQueue.empty() && !backwardQueue.empty()) {
// 从起点开始的搜索
int forwardSize = forwardQueue.size();
for (int i = 0; i < forwardSize; i++) {
int current = forwardQueue.front();
forwardQueue.pop();
for (int neighbor : adjacencyList[current]) {
if (!forwardVisited[neighbor]) {
forwardQueue.push(neighbor);
forwardVisited[neighbor] = true;
forwardParent[neighbor] = current;
}
}
}
// 从终点开始的搜索
int backwardSize = backwardQueue.size();
for (int i = 0; i < backwardSize; i++) {
int current = backwardQueue.front();
backwardQueue.pop();
for (int neighbor : adjacencyList[current]) {
if (!backwardVisited[neighbor]) {
backwardQueue.push(neighbor);
backwardVisited[neighbor] = true;
backwardParent[neighbor] = current;
}
}
}
// 检查相遇的节点
for (int i = 0; i < vertices; i++) {
if (forwardVisited[i] && backwardVisited[i]) {
result.push_back(i);
// 构造路径
int currentNode = i;
while (currentNode != start) {
result.push_back(forwardParent[currentNode]);
currentNode = forwardParent[currentNode];
}
reverse(result.begin(), result.end());
currentNode = i;
while (currentNode != end) {
result.push_back(backwardParent[currentNode]);
currentNode = backwardParent[currentNode];
}
return result;
}
}
}
return result;
}
int main() {
int vertices = 6;
Graph graph(vertices);
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(1, 3);
graph.addEdge(1, 4);
graph.addEdge(2, 4);
graph.addEdge(3, 5);
int start = 0;
int end = 5;
vector<int> shortestPath = graph.bidirectionalBFS(start, end);
if (!shortestPath.empty()) {
cout << "Shortest path from " << start << " to " << end << ": ";
for (int node : shortestPath) {
cout << node << " ";
}
cout << endl;
} else {
cout << "No path found from " << start << " to " << end << "." << endl;
}
return 0;
}