深度优先搜索(DFS, Depth-First Search)是一种用于遍历或搜索树或图的算法。在搜索过程中,DFS会尽可能深地搜索图的分支。当节点v的所在边都已被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这个过程一直进行到已发现从源节点可达的所有节点为止。
深度优先搜索的基本思想
- 从一个顶点v开始,访问此顶点,然后从此顶点未被访问的邻接点中选择一个顶点w,继续访问。
- 重复上述过程,直到所有从v可达的顶点都被访问过。
- 若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作为起点,重复上述过程,直到图中所有顶点都被访问过为止。
深度优先搜索的伪代码
DFS(v):
标记 v 为已访问
对于 v 的每个未被访问的邻接点 w
DFS(w)
深度优先搜索的C++实现
以下是一个使用邻接表表示图并使用递归实现的DFS的C++示例代码:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
// 图类
class Graph {
int V; // 顶点数
list<int> *adj; // 邻接表
public:
Graph(int V); // 构造函数
void addEdge(int v, int w); // 添加边
void DFSUtil(int v, vector<bool> &visited); // DFS辅助函数
void DFS(int v); // DFS的外部接口
};
Graph::Graph(int V) {
this->V = V;
adj = new list<int>[V];
}
void Graph::addEdge(int v, int w) {
adj[v].push_back(w); // 添加一条从v到w的边
}
void Graph::DFSUtil(int v, vector<bool> &visited) {
// 标记当前节点为已访问
visited[v] = true;
cout << v << " ";
// 递归访问所有未访问的邻接点
list<int>::iterator i;
for (i = adj[v].begin(); i != adj[v].end(); ++i)
if (!visited[*i])
DFSUtil(*i, visited);
}
void Graph::DFS(int v) {
// 标记所有顶点为未访问
vector<bool> visited(V, false);
// 调用辅助函数进行DFS遍历
DFSUtil(v, visited);
}
// 测试代码
int main() {
// 创建一个图实例
Graph g(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);
cout << "从顶点 2 开始的深度优先遍历(DFS):" << endl;
g.DFS(2);
return 0;
}
深度优先搜索的实例
假设我们有以下图:
(0)
/ | \
(1) (2)
\ | /
(3)
边为:(0,1), (0,2), (1,2), (2,0), (2,3), (3,3)。
如果我们从顶点2开始进行DFS,访问顺序可能是:2, 0, 1, 3(注意,访问顺序可能因实现方式而异,因为图是无向的,且可能存在环)。
深度优先搜索的想象(概念图)
你可以想象上述图在DFS过程中的遍历过程。从顶点2开始,首先访问2,然后访问2的一个未访问的邻接点(比如0),接着从0访问其未访问的邻接点(比如1),最后回到2访问其另一个未访问的邻接点(比如3)。注意,由于存在从2到0的边,DFS可能会再次访问0,但在这个例子中,我们假设访问过的节点不会被重复访问(除非有显式需要,比如寻找环)。