在无权图中,广度优先搜索(BFS)是解决最短路径问题的高效算法。接下来博主从专业角度深入探讨其实现细节,并给出C++代码示例:
目录
一、核心原理
二、算法步骤
三、C++实现关键点
1. 数据结构
2. 边界检查
3. 路径回溯(可选)
四、代码实现
五、路径回溯实现
六、复杂度分析
七、适用场景与限制
一、核心原理
BFS按层遍历节点,确保首次到达目标节点的路径是最短的。其核心特性为:
-
队列管理:先进先出(FIFO)保证按层扩展。
-
访问标记:避免重复访问,防止环路。
-
距离记录:每个节点的距离为父节点距离加1。
二、算法步骤
-
初始化:起点入队,标记距离为0。
-
遍历队列:逐层处理节点,遍历所有合法邻居。
-
终止条件:到达终点时返回距离;队列为空则表示不可达。
三、C++实现关键点
1. 数据结构
-
队列:存储待处理节点,使用
queue<pair<int, int>>
。 -
距离矩阵:记录每个节点的最短距离,初始化为-1表示未访问。
-
方向数组:定义移动方向(如4方向或8方向)。
int dx[] = {-1, 1, 0, 0}; // 上下左右
int dy[] = {0, 0, -1, 1};
2. 边界检查
确保新坐标在网格范围内,且节点可访问(非障碍、未访问)。
3. 路径回溯(可选)
通过父节点矩阵记录路径,回溯时从终点反向追踪至起点。
四、代码实现
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int bfsShortestPath(vector<vector<int>>& grid, pair<int, int> start, pair<int, int> end) {
int n = grid.size();
if (n == 0) return -1;
int m = grid[0].size();
queue<pair<int, int>> q;
vector<vector<int>> dist(n, vector<int>(m, -1));
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
// 初始化起点
q.push(start);
dist[start.first][start.second] = 0;
while (!q.empty()) {
auto curr = q.front();
q.pop();
// 到达终点
if (curr.first == end.first && curr.second == end.second) {
return dist[curr.first][curr.second];
}
// 遍历四个方向
for (int i = 0; i < 4; ++i) {
int x = curr.first + dx[i];
int y = curr.second + dy[i];
// 检查新坐标是否合法
if (x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == 0 && dist[x][y] == -1) {
dist[x][y] = dist[curr.first][curr.second] + 1;
q.push({x, y});
}
}
}
return -1; // 不可达
}
// 示例用法
int main() {
vector<vector<int>> grid = {
{0, 1, 0, 0},
{0, 0, 0, 1},
{1, 1, 0, 0},
{0, 0, 0, 0}
};
pair<int, int> start = {0, 0};
pair<int, int> end = {3, 3};
int shortest = bfsShortestPath(grid, start, end);
if (shortest != -1) {
cout << "最短路径长度: " << shortest << endl;
} else {
cout << "无法到达终点!" << endl;
}
return 0;
}
五、路径回溯实现
扩展代码以记录路径:
vector<pair<int, int>> getPath(vector<vector<pair<int, int>>>& parent, pair<int, int> start, pair<int, int> end) {
vector<pair<int, int>> path;
pair<int, int> curr = end;
while (curr != start) {
path.push_back(curr);
curr = parent[curr.first][curr.second];
}
path.push_back(start);
reverse(path.begin(), path.end());
return path;
}
// 在BFS函数中添加父节点记录
vector<vector<pair<int, int>>> parent(n, vector<pair<int, int>>(m, {-1, -1}));
// ...
if (条件满足) {
parent[x][y] = curr;
}
// 找到终点后调用getPath
六、复杂度分析
-
时间复杂度:O(N×M),每个节点处理一次。
-
空间复杂度:O(N×M),队列和距离矩阵的开销。
七、适用场景与限制
-
适用:无权图、网格迷宫、社交网络层级关系。
-
限制:仅处理无权图,带权图需改用Dijkstra或A*算法。
通过以上实现,BFS能够高效解决无权图中的最短路径问题。正确管理队列和状态标记是保证算法正确性的关键。