数据结构与算法之广度优先算法
广度优先搜索(Breadth First Search,BFS)是一种图形搜索算法,用于遍历或搜索树或图的数据结构。其主要思想是从起点开始,依次遍历距离该节点最近的所有节点,再依次遍历距离该节点次近的所有节点,以此类推,直到找到目标节点或遍历完整个图。
具体实现上,BFS通常使用队列(Queue)数据结构存储待遍历的节点。从起点开始,将其加入队列中。之后,不断从队列中取出队首节点,并依次遍历其所有未被遍历的邻居节点。将这些邻居节点加入队列中,直到遍历到目标节点或队列为空为止。
BFS算法的优点是可以找到最短路径,即从起点到目标节点的最少步数。同时,BFS算法还可以用于解决一些应用问题,例如迷宫问题、社交网络分析等。
一、C语言之数据结构与算法之广度优先算法源码实现及详解
下面是一个示例C语言代码实现BFS算法:
#include <stdio.h>
#include <stdbool.h>
#define MAX_VERTICES 100 // 最大节点数量
typedef struct {
int data[MAX_VERTICES]; // 节点数据
int size; // 节点数量
} Queue;
typedef struct {
int vertices[MAX_VERTICES][MAX_VERTICES]; // 图的邻接矩阵
int n; // 节点数量
} Graph;
// 初始化队列
void initQueue(Queue *q) {
q->size = 0;
}
// 判断队列是否为空
bool isQueueEmpty(Queue *q) {
return q->size == 0;
}
// 入队
void enqueue(Queue *q, int data) {
q->data[q->size++] = data;
}
// 出队
int dequeue(Queue *q) {
int data = q->data[0];
q->size--;
for (int i = 0; i < q->size; i++) {
q->data[i] = q->data[i + 1];
}
return data;
}
// BFS算法
void bfs(int start, Graph *g, bool visited[]) {
Queue q;
initQueue(&q);
visited[start] = true;
enqueue(&q, start);
while (!isQueueEmpty(&q)) {
int currentVertex = dequeue(&q);
printf("%d ", currentVertex);
for (int i = 0; i < g->n; i++) {
if (g->vertices[currentVertex][i] == 1 && !visited[i]) {
visited[i] = true;
enqueue(&q, i);
}
}
}
}
int main() {
Graph g;
g.n = 6;
// 初始化邻接矩阵
for (int i = 0; i < g.n; i++) {
for (int j = 0; j < g.n; j++) {
g.vertices[i][j] = 0;
}
}
// 添加边
g.vertices[0][1] = 1;
g.vertices[0][2] = 1;
g.vertices[1][2] = 1;
g.vertices[2][0] = 1;
g.vertices[2][3] = 1;
g.vertices[3][3] = 1;
g.vertices[4][5] = 1;
g.vertices[5][4] = 1;
bool visited[MAX_VERTICES] = { false };
bfs(2, &g, visited);
return 0;
}
在此示例代码中:
- 使用邻接矩阵来表示图,表示节点之间的关系。
- 使用队列来存储待遍历的节点,需要实现队列的入队和出队操作。
- 使用 visited 数组来表示每个节点是否已经被遍历,防止重复遍历。
在main()函数中,建立一个简单的图,并使用广度优先搜索算法从节点2开始遍历整个图。
二、C++语言之数据结构与算法之广度优先算法源码实现及详解
下面是一个示例C++代码实现BFS算法:
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
const int MAX_VERTICES = 100; // 最大节点数量
typedef vector<int> vi;
typedef vector<vi> vv;
bool visited[MAX_VERTICES]; // 表示每个节点是否已经被遍历,防止重复遍历
// BFS算法
void bfs(int start, const vv &graph) {
queue<int> q;
visited[start] = true;
q.push(start);
while (!q.empty()) {
int currentVertex = q.front();
q.pop();
cout << currentVertex << " ";
for (int i = 0; i < graph[currentVertex].size(); i++) {
int neighbor = graph[currentVertex][i];
if (!visited[neighbor]) {
visited[neighbor] = true;
q.push(neighbor);
}
}
}
}
int main() {
vv graph(6); // 建立一个节点数量为6的图
// 添加边
graph[0].push_back(1);
graph[0].push_back(2);
graph[1].push_back(2);
graph[2].push_back(0);
graph[2].push_back(3);
graph[3].push_back(3);
graph[4].push_back(5);
graph[5].push_back(4);
memset(visited, false, sizeof(visited)); // 初始化visited数组
bfs(2, graph); // 从节点2开始BFS遍历图
return 0;
}
在此示例代码中:
- 使用邻接表来表示图,表示节点之间的关系。
- 使用队列来存储待遍历的节点,使用STL库中的queue实现,无需手动实现队列的操作。
- 使用 visited 数组来表示每个节点是否已经被遍历,防止重复遍历。
在main()函数中,建立一个简单的图,并使用广度优先搜索算法从节点2开始遍历整个图。
三、java语言之数据结构与算法之广度优先算法源码实现及详解
广度优先算法(Breadth First Search,BFS)是一种常用的图形搜索算法,它从图形的起始节点开始,一层层地向外扩展搜索,直到找到目标节点或者整张图的节点都遍历完毕。BFS算法具有以下特点:
-
广度优先搜索是一种盲目搜索策略,不考虑各个节点之间的距离和权重,只关注节点之间的连通性。
-
BFS算法可以用于寻找最短路径,因为它先搜索到的一定是距离起点最近的节点。
-
BFS算法需要使用队列这种数据结构进行实现。
下面就来介绍一下BFS算法的源码实现及详解:
import java.util.ArrayDeque;
import java.util.Queue;
public class BFS {
/* 定义节点类 */
static class Node{
int x, y; // 节点的坐标
Node(int x, int y){
this.x = x;
this.y = y;
}
}
public static void main(String[] args) {
/* 定义迷宫地图 */
char[][] maze = {
{'#', '#', '#', '#', '#', '#', '#', '#', '#', '#'},
{'#', '.', '#', '.', '.', '.', '#', '.', '.', '#'},
{'#', '.', '#', '#', '.', '.', '#', '.', '#', '#'},
{'#', '.', '.', '.', '.', '.', '.', '.', '.', '#'},
{'#', '#', '#', '#', '#', '.', '#', '#', '.', '#'},
{'#', '.', '.', '.', '.', '.', '#', '#', '#', '#'},
{'#', '#', '#', '#', '.', '.', '.', '.', '.', '#'},
{'#', '.', '.', '#', '.', '#', '.', '#', '.', '#'},
{'#', '.', '.', '.', '#', '.', '#', '.', '.', '#'},
{'#', '#', '#', '#', '#', '#', '#', '#', '#', '#'},
};
/* 定义起点和终点 */
Node start = new Node(1, 1);
Node end = new Node(8, 8);
/* 定义队列 */
Queue<Node> queue = new ArrayDeque<>();
queue.add(start);
/* 定义数组记录每个节点是否被访问过 */
boolean[][] visited = new boolean[10][10];
visited[start.x][start.y] = true;
/* 定义数组记录每个节点的父节点 */
Node[][] parent = new Node[10][10];
parent[start.x][start.y] = start;
/* 开始广度优先搜索 */
while(!queue.isEmpty()){
/* 取出队列的头节点 */
Node cur = queue.poll();
/* 判断是否到达终点 */
if(cur.x == end.x && cur.y == end.y) break;
/* 遍历当前节点的所有邻居节点 */
int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 定义四个方向
for(int[] dir : dirs){
int nextX = cur.x + dir[0];
int nextY = cur.y + dir[1];
/* 判断下一个节点是否越界或者已经访问过 */
if(nextX < 0 || nextX >= maze.length || nextY < 0 || nextY >= maze[0].length || visited[nextX][nextY] || maze[nextX][nextY] == '#') continue;
/* 添加下一个节点到队列中 */
queue.add(new Node(nextX, nextY));
visited[nextX][nextY] = true;
parent[nextX][nextY] = cur;
}
}
/* 输出最短路径 */
Node cur = end;
while(cur != start){
System.out.print("(" + cur.x + "," + cur.y + ") <- ");
cur = parent[cur.x][cur.y];
}
System.out.println("(" + start.x + "," + start.y + ")");
}
}
以上代码是一个简单的迷宫求解问题,我们将起点和终点之间的最短路径用BFS算法求出并输出。下面对代码中的主要部分进行详解:
- 定义节点类
static class Node{
int x, y; // 节点的坐标
Node(int x, int y){
this.x = x;
this.y = y;
}
}
节点类包含一个x、y坐标,表示节点在迷宫地图中的位置。
- 定义队列
Queue<Node> queue = new ArrayDeque<>();
queue.add(start);
BFS算法需要使用队列来进行实现,我们使用Java标准库中的ArrayDeque来实现队列。将起点加入队列中。
- 定义数组记录每个节点是否被访问过
boolean[][] visited = new boolean[10][10];
visited[start.x][start.y] = true;
为了避免重复访问节点,我们需要使用一个二维布尔数组visited来记录每个节点是否被访问过。将起点标记为已访问。
- 定义数组记录每个节点的父节点
Node[][] parent = new Node[10][10];
parent[start.x][start.y] = start;
在搜索过程中,我们需要记录每个节点的父节点,以便在搜索结束后回溯寻找最短路径。我们使用一个二维Node数组parent来记录每个节点的父节点。将起点的父节点设置为其自身。
- 开始广度优先搜索
while(!queue.isEmpty()){
/* 取出队列的头节点 */
Node cur = queue.poll();
/* 判断是否到达终点 */
if(cur.x == end.x && cur.y == end.y) break;
/* 遍历当前节点的所有邻居节点 */
int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 定义四个方向
for(int[] dir : dirs){
int nextX = cur.x + dir[0];
int nextY = cur.y + dir[1];
/* 判断下一个节点是否越界或者已经访问过 */
if(nextX < 0 || nextX >= maze.length || nextY < 0 || nextY >= maze[0].length || visited[nextX][nextY] || maze[nextX][nextY] == '#') continue;
/* 添加下一个节点到队列中 */
queue.add(new Node(nextX, nextY));
visited[nextX][nextY] = true;
parent[nextX][nextY] = cur;
}
}
从队列中取出一个节点,遍历其所有邻居节点,将没有访问过的节点加入队列中,并标记其父节点。如果找到了终点,则退出循环。
- 输出最短路径
Node cur = end;
while(cur != start){
System.out.print("(" + cur.x + "," + cur.y + ") <- ");
cur = parent[cur.x][cur.y];
}
System.out.println("(" + start.x + "," + start.y + ")");
通过回溯每个节点的父节点,从终点一直走到起点,输出最短路径。
总结:
BFS算法是一种常用的图形搜索算法,它的实现需要用到队列、数组等数据结构。在使用BFS算法时,需要定义节点类、队列、visited、parent等数组或变量,然后按照广度优先的顺序逐层遍历每个节点,记录每个节点的父节点,最后回溯寻找最短路径。