DFS(深度优先搜索)和BFS(广度优先搜索)
DFS(深度优先搜索)和BFS(广度优先搜索)是两种常用的图或树遍历算法。它们在许多计算机科学问题中都有应用,如路径查找、连通性检测和子图匹配等。以下是对这两种算法的详细解释及示例。
深度优先搜索(DFS)
DFS 是一种遍历或搜索树或图的算法。其主要思想是从起始节点开始,沿着每一个分支尽可能深入地搜索,直到找到目标节点或没有更多节点可访问,然后回溯并继续搜索其他分支。
DFS 算法步骤:
- 从起始节点开始,标记该节点已访问。
- 访问该节点的每一个邻接节点。
- 对每一个未访问的邻接节点,递归调用 DFS。
- 如果所有邻接节点都已访问,则回溯到前一个节点。
DFS 示例(以图为例):
假设有以下图:
A
/ \
B C
/ \ \
D E F
DFS 遍历顺序可能是:A -> B -> D -> E -> C -> F
示例代码(C 语言):
#include <stdio.h>
#include <stdlib.h>
#define MAX 100 // 定义最大节点数量
int visited[MAX]; // 记录每个节点是否被访问过
int adjMatrix[MAX][MAX]; // 邻接矩阵,表示图的连接情况
int n; // 节点数量
// 深度优先搜索函数
void DFS(int vertex) {
printf("%d ", vertex); // 打印当前访问的节点
visited[vertex] = 1; // 标记当前节点为已访问
// 遍历所有节点,检查是否与当前节点相邻且未被访问
for (int i = 0; i < n; i++) {
if (adjMatrix[vertex][i] == 1 && !visited[i]) {
DFS(i); // 递归调用 DFS,访问相邻节点
}
}
}
int main() {
n = 6; // 设置图中节点的数量
// 定义图的边(无向图)
int edges[7][2] = {{0, 1}, {0, 2}, {1, 3}, {1, 4}, {2, 5}, {3, 4}, {4, 5}};
// 初始化邻接矩阵
for (int i = 0; i < 7; i++) {
int u = edges[i][0];
int v = edges[i][1];
adjMatrix[u][v] = 1;
adjMatrix[v][u] = 1; // 对于无向图,邻接矩阵是对称的
}
// 初始化 visited 数组,设置所有节点为未访问
for (int i = 0; i < n; i++) {
visited[i] = 0;
}
printf("DFS traversal: ");
DFS(0); // 从节点 0 开始进行深度优先搜索
return 0; // 程序结束
}
广度优先搜索(BFS)
BFS 是一种遍历或搜索树或图的算法。其主要思想是从起始节点开始,首先访问所有邻接节点,然后再按层次访问每个邻接节点的邻接节点。
BFS 算法步骤:
- 从起始节点开始,标记该节点已访问并将其加入队列。
- 从队列中取出一个节点,访问其所有未访问的邻接节点,将它们标记为已访问并加入队列。
- 重复步骤 2 直到队列为空。
BFS 示例(以图为例):
假设有以下图:
A
/ \
B C
/ \ \
D E F
BFS 遍历顺序是:A -> B -> C -> D -> E -> F
示例代码(C 语言):
#include <stdio.h>
#include <stdlib.h>
#define MAX 100 // 定义最大节点数量
int visited[MAX]; // 记录每个节点是否被访问过
int adjMatrix[MAX][MAX]; // 邻接矩阵,表示图的连接情况
int n; // 节点数量
// 广度优先搜索函数
void BFS(int start) {
int queue[MAX], front = 0, rear = 0; // 定义队列及其前后指针
printf("%d ", start); // 打印起始节点
visited[start] = 1; // 标记起始节点为已访问
queue[rear++] = start; // 将起始节点加入队列
// 当队列不为空时,循环进行广度优先搜索
while (front != rear) {
int vertex = queue[front++]; // 从队列中取出一个节点
for (int i = 0; i < n; i++) {
// 检查是否与当前节点相邻且未被访问
if (adjMatrix[vertex][i] == 1 && !visited[i]) {
printf("%d ", i); // 打印访问的节点
visited[i] = 1; // 标记该节点为已访问
queue[rear++] = i; // 将该节点加入队列
}
}
}
}
int main() {
n = 6; // 设置图中节点的数量
// 定义图的边(无向图)
int edges[7][2] = {{0, 1}, {0, 2}, {1, 3}, {1, 4}, {2, 5}, {3, 4}, {4, 5}};
// 初始化邻接矩阵
for (int i = 0; i < 7; i++) {
int u = edges[i][0];
int v = edges[i][1];
adjMatrix[u][v] = 1;
adjMatrix[v][u] = 1; // 对于无向图,邻接矩阵是对称的
}
// 初始化 visited 数组,设置所有节点为未访问
for (int i = 0; i < n; i++) {
visited[i] = 0;
}
printf("BFS traversal: ");
BFS(0); // 从节点 0 开始进行广度优先搜索
return 0; // 程序结束
}
对比 DFS 和 BFS
-
搜索策略:
- DFS:沿着树或图的每一个分支尽可能深地搜索。
- BFS:按层次逐层搜索,每层节点都被访问后再访问下一层。
-
使用数据结构:
- DFS:通常使用栈(递归调用栈)。
- BFS:使用队列。
-
适用场景:
- DFS:适用于需要搜索整个路径或所有可能情况的问题,如迷宫求解、拓扑排序等。
- BFS:适用于搜索最短路径或层次结构的问题,如最短路径求解、广度优先遍历等。