广度优先遍历(Breadth-First Search,BFS)是一种遍历或搜索数据结构(如树或图)的算法。它从根节点开始,依次遍历同一级别的所有节点,然后再逐级遍历下一级别的节点,直到遍历完整个结构。
BFS使用队列(queue)来实现遍历过程。从根节点开始,将根节点入队,然后进入循环。循环中取出队列首部节点,访问它的所有邻居节点并将其入队,然后重复上述步骤,直到队列为空。
BFS的时间复杂度为O(N),其中N代表节点个数。因为它需要遍历整个结构中的每个节点一次。BFS的空间复杂度也为O(N),因为需要使用队列来存储节点。
BFS的应用非常广泛。例如,可以用它来解决最短路径问题、迷宫问题等。由于BFS能够找到最短路径,因此它也被广泛用于人工智能、游戏设计、网络路由等领域。
一、C 实现 广度优先遍历 及代码详解
广度优先遍历是一种图遍历算法,也称为“宽度优先搜索”或“横向优先搜索”。该算法从图的某个起始节点开始遍历,先访问该节点,然后访问该节点的所有相邻节点,再访问相邻节点的相邻节点,以此类推,直到遍历完所有可达节点。广度优先遍历一般使用队列来实现。
以下是C语言实现广度优先遍历的代码及详解:
#include <stdio.h>
#include <stdlib.h>
#define MAX_VERTEX_NUM 100 // 图中顶点的最大数量
typedef struct node{// 邻接表中的链表节点
int adjvex; // 邻接点在数组中的下标
struct node *next; // 指向下一个邻接点
} EdgeNode;
typedef struct VertexNode{// 邻接表中的顶点节点
int data;// 顶点的数据
EdgeNode *firstEdge;// 指向第一条邻接边
} VertexNode;
typedef struct Graph{// 定义图结构
VertexNode adjList[MAX_VERTEX_NUM];// 邻接表
int visited[MAX_VERTEX_NUM];// 标记数组,用于记录每个顶点是否被访问过
int vertexNum;// 顶点数目
int edgeNum;// 边数目
} Graph;
typedef struct Queue{// 定义队列结构
int *data;// 队列中的数据
int front, rear;// 队头和队尾指针
} Queue;
void initQueue(Queue *queue, int size){// 初始化队列
queue->data = (int*)malloc(size * sizeof(int));
queue->front = queue->rear = 0;
}
void enQueue(Queue *queue, int element){// 入队
queue->data[queue->rear++] = element;
}
int deQueue(Queue *queue){// 出队
return queue->data[queue->front++];
}
int isQueueEmpty(Queue *queue){// 判断队列是否为空
return queue->front == queue->rear;
}
void createGraph(Graph *g){// 创建图
printf("请输入顶点数目和边数目:");
scanf("%d%d", &g->vertexNum, &g->edgeNum);
printf("请输入每个顶点的数据:");
for (int i = 0; i < g->vertexNum; i++){
scanf("%d", &g->adjList[i].data);
g->adjList[i].firstEdge = NULL;// 初始化邻接表
}
printf("请输入每条边连接的两个顶点在数组中的下标:\n");
for (int i = 0; i < g->edgeNum; i++){
int u, v;
scanf("%d%d", &u, &v);
// 添加边
EdgeNode *newEdge = (EdgeNode*)malloc(sizeof(EdgeNode));
newEdge->adjvex = v;
newEdge->next = g->adjList[u].firstEdge;
g->adjList[u].firstEdge = newEdge;
newEdge = (EdgeNode*)malloc(sizeof(EdgeNode));
newEdge->adjvex = u;
newEdge->next = g->adjList[v].firstEdge;
g->adjList[v].firstEdge = newEdge;
}
}
void BFS(Graph *g, int start){// 广度优先遍历
Queue queue;
initQueue(&queue, g->vertexNum);
g->visited[start] = 1;// 标记起始点为已经访问
printf("%d ", g->adjList[start].data);
enQueue(&queue, start);
while (!isQueueEmpty(&queue)){
int u = deQueue(&queue);
for (EdgeNode *e = g->adjList[u].firstEdge; e != NULL; e = e->next){
int v = e->adjvex;
if (!g->visited[v]){
g->visited[v] = 1;
printf("%d ", g->adjList[v].data);
enQueue(&queue, v);
}
}
}
}
int main(){
Graph g;
createGraph(&g);
printf("广度优先遍历结果为:");
for (int i = 0; i < g.vertexNum; i++){
g.visited[i] = 0;// 初始化标记数组
}
BFS(&g, 0);// 从第0个顶点开始遍历
printf("\n");
return 0;
}
代码详解:
-
定义邻接表中的链表节点和顶点节点
typedef struct node{// 邻接表中的链表节点 int adjvex; // 邻接点在数组中的下标 struct node *next; // 指向下一个邻接点 } EdgeNode; typedef struct VertexNode{// 邻接表中的顶点节点 int data;// 顶点的数据 EdgeNode *firstEdge;// 指向第一条邻接边 } VertexNode;
-
定义图结构
typedef struct Graph{// 定义图结构 VertexNode adjList[MAX_VERTEX_NUM];// 邻接表 int visited[MAX_VERTEX_NUM];// 标记数组,用于记录每个顶点是否被访问过 int vertexNum;// 顶点数目 int edgeNum;// 边数目 } Graph;
-
创建图
void createGraph(Graph *g){// 创建图 printf("请输入顶点数目和边数目:"); scanf("%d%d", &g->vertexNum, &g->edgeNum); printf("请输入每个顶点的数据:"); for (int i = 0; i < g->vertexNum; i++){ scanf("%d", &g->adjList[i].data); g->adjList[i].firstEdge = NULL;// 初始化邻接表 } printf("请输入每条边连接的两个顶点在数组中的下标:\n"); for (int i = 0; i < g->edgeNum; i++){ int u, v; scanf("%d%d", &u, &v); // 添加边 EdgeNode *newEdge = (EdgeNode*)malloc(sizeof(EdgeNode)); newEdge->adjvex = v; newEdge->next = g->adjList[u].firstEdge; g->adjList[u].firstEdge = newEdge; newEdge = (EdgeNode*)malloc(sizeof(EdgeNode)); newEdge->adjvex = u; newEdge->next = g->adjList[v].firstEdge; g->adjList[v].firstEdge = newEdge; } }
先输入顶点数目和边数目,然后输入每个顶点的数据。初始化邻接表,每个顶点的第一条邻接边指向NULL。接着输入每条边连接的两个顶点在数组中的下标,将这两个顶点之间添加边。
-
初始化队列
void initQueue(Queue *queue, int size){// 初始化队列 queue->data = (int*)malloc(size * sizeof(int)); queue->front = queue->rear = 0; }
根据队列大小动态分配内存,并将队头和队尾指针都初始化为0。
-
入队
void enQueue(Queue *queue, int element){// 入队 queue->data[queue->rear++] = element; }
将元素加入队尾。
-
出队
int deQueue(Queue *queue){// 出队 return queue->data[queue->front++]; }
返回队头元素并将队头指针向后移一位。
-
判断队列是否为空
int isQueueEmpty(Queue *queue){// 判断队列是否为空 return queue->front == queue->rear; }
如果队头和队尾指针相等,说明队列为空。
-
广度优先遍历
void BFS(Graph *g, int start){// 广度优先遍历
Queue queue;
initQueue(&queue, g->vertexNum);
g->visited[start] = 1;// 标记起始点为已经访问
printf("%d ", g->adjList[start].data);
enQueue(&queue,
二、C++ 实现 广度优先遍历 及代码详解
广度优先遍历(BFS)是一种图遍历算法,从图的某个顶点开始遍历,先遍历它的所有相邻节点,然后依次遍历它们的相邻节点,直到遍历完整个图。BFS 通常用队列来实现。
以下是一个 C++ 实现 BFS 的代码示例:
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
void bfs(vector<vector<int>>& graph, int start) {
vector<bool> visited(graph.size(), false);
queue<int> q;
visited[start] = true;
q.push(start);
while (!q.empty()) {
int curr = q.front();
q.pop();
cout << curr << " ";
for (int i = 0; i < graph[curr].size(); i++) {
int next = graph[curr][i];
if (!visited[next]) {
visited[next] = true;
q.push(next);
}
}
}
cout << endl;
}
int main() {
vector<vector<int>> graph = {{1, 2}, {2, 3}, {3, 4}, {4, 5}, {5}};
bfs(graph, 0);
return 0;
}
这段代码使用了一个二维向量 graph
来表示图的邻接表,其中 graph[i]
表示节点 i
的相邻节点列表。 bfs
函数以一个起始节点 start
作为参数,使用一个队列来遍历整个图。每次从队列头取出一个节点 curr
,遍历它的相邻节点,并将未访问过的相邻节点加入队列中。为了避免重复访问节点,使用一个布尔型数组 visited
来记录每个节点是否已经被访问过。
在 main
函数中,定义了一个以 0
作为起始节点的图,并调用 bfs
函数来遍历整个图。
注意:这只是一个简单的示例,实际应用中需要根据实际情况进行修改和优化。
三、Java 实现 广度优先遍历 及代码详解
广度优先遍历(BFS)是一种图遍历算法,它从图的起始点开始,依次访问所有可以到达的节点。BFS 通常用队列来实现。
下面是 Java 实现广度优先遍历的代码,具体解释可以看代码注释:
import java.util.LinkedList;
import java.util.Queue;
public class BFS {
public static void bfs(int[][] graph, int start) {
// 定义一个队列来存储待访问的节点
Queue<Integer> queue = new LinkedList<>();
// 定义一个数组来记录节点是否已被访问过
boolean[] visited = new boolean[graph.length];
// 将起点加入队列,标记已访问
queue.offer(start);
visited[start] = true;
while (!queue.isEmpty()) {
// 取出队头节点
int curr = queue.poll();
System.out.print(curr + " ");
// 遍历与当前节点相邻的所有节点
for (int i = 0; i < graph[curr].length; i++) {
int neighbor = graph[curr][i];
// 如果该节点未被访问过,则加入队列并标记已访问
if (!visited[neighbor]) {
queue.offer(neighbor);
visited[neighbor] = true;
}
}
}
}
public static void main(String[] args) {
int[][] graph = {
// 0 1 2 3 4 5
{0, 1, 1, 0, 0, 0}, // 0
{1, 0, 0, 1, 1, 0}, // 1
{1, 0, 0, 0, 1, 1}, // 2
{0, 1, 0, 0, 1, 0}, // 3
{0, 1, 1, 1, 0, 1}, // 4
{0, 0, 1, 0, 1, 0} // 5
};
bfs(graph, 0);
}
}
上面代码中,graph
数组表示一个无向图的邻接矩阵,bfs
方法用来实现 BFS 遍历。在 bfs
方法中,我们先定义一个队列 queue
来存储待访问的节点,一个 boolean 数组 visited
用来记录节点是否已被访问过。然后将起点加入队列,并标记已访问。接下来,用一个 while 循环不断从队列中取出队头节点 curr
,输出其值,然后遍历与其相邻的所有节点,如果该节点未被访问过,则加入队列并标记已访问。循环直到队列为空。
在主函数中,我们创建一个表示无向图的邻接矩阵 graph
,然后调用 bfs
方法进行遍历,起点是节点 0。