C++深度优先搜索(DFS)算法的全面解读
深度优先搜索(DFS)是一种用于遍历或搜索树或图的算法。它是一种系统地访问所有顶点的策略,使得可以进行各种运算,如路径查找、连通分量的确定等。下面是DFS在C++中的全面解读,包括其理论、实现和应用。
理论概述
DFS的基本思想是尽可能深地搜索树或图的分支。它是一种贪心算法,未遇到死胡同之前尽量深入。因此,在每访问一个节点时,会继续访问其未被访问的子节点,直到所有子节点都被访问过才回溯。
DFS的特点:
- 递归性:DFS可以天然应用递归思想,因为每次访问一个节点时,会进入该节点的分支,完成后回溯到上一个节点。
- 堆栈结构:在实现过程中,通过系统栈(递归)或显式使用堆栈来记录路径。
- 时间复杂度:对于一个图(V个顶点,E条边),DFS的时间复杂度为O(V + E)。
- 空间复杂度:由于需要存储访问状态和递归栈,空间复杂度通常为O(V)。
基本实现
DFS可以通过递归和非递归(使用栈)两种方式实现。下面我们将分别展示两种实现方法。
递归实现
#include <iostream>
#include <vector>
void dfsRec(const std::vector<std::vector<int>>& graph, int node, std::vector<bool>& visited) {
visited[node] = true;
std::cout << node << " ";
for (int neighbor : graph[node]) {
if (!visited[neighbor]) {
dfsRec(graph, neighbor, visited);
}
}
}
int main() {
const int numVertices = 5;
std::vector<std::vector<int>> graph(numVertices);
// 构建图(无向图)
graph[0] = {1, 4};
graph[1] = {0, 2, 3};
graph[2] = {1};
graph[3] = {1, 4};
graph[4] = {0, 3};
std::vector<bool> visited(numVertices, false);
// 从节点 0 开始DFS
std::cout << "DFS starting from node 0:" << std::endl;
dfsRec(graph, 0, visited);
return 0;
}
非递归实现
#include <iostream>
#include <vector>
#include <stack>
void dfsIterative(const std::vector<std::vector<int>>& graph, int startNode) {
std::vector<bool> visited(graph.size(), false);
std::stack<int> s;
s.push(startNode);
while (!s.empty()) {
int node = s.top();
s.pop();
if (!visited[node]) {
std::cout << node << " ";
visited[node] = true;
}
for (int neighbor : graph[node]) {
if (!visited[neighbor]) {
s.push(neighbor);
}
}
}
}
int main() {
const int numVertices = 5;
std::vector<std::vector<int>> graph(numVertices);
// 构建图(无向图)
graph[0] = {1, 4};
graph[1] = {0, 2, 3};
graph[2] = {1};
graph[3] = {1, 4};
graph[4] = {0, 3};
std::cout << "DFS (iterative) starting from node 0:" << std::endl;
dfsIterative(graph, 0);
return 0;
}
应用场景
- 路径查找:在迷宫或网络中寻找路径。
- 连通分量:确定图中连通的分量数量。
- 拓扑排序:用于有向无环图的排序。
- 二分图检测:判断图是否为二分图。
- 检测环:在无向图和有向图中检测是否存在环。
注意事项
- 在处理大型图时,需要注意递归栈的深度限制,以避免栈溢出。
- 确保正确维护访问状态,以避免重复访问节点或陷入无限循环。
通过这种方式,DFS可以被灵活地应用于解决图论相关问题和其他需要搜索的场景。