深度优先搜索算法
深度优先搜索算法是一种用于图形和树的遍历算法。它通过沿着树的深度(而不是广度)努力地搜索最佳解来实现,即找到最优解,或者覆盖树中的所有节点。算法的主要特征是它以一种比较深的方式去搜索问题的解空间,而不是从上到下进行搜索。
算法流程
树的每个节点都被记录下来,作为搜索的初始节点,从第一个节点开始,搜索它的子节点直到子节点没有子节点,然后回到父节点,搜索它的兄弟节点,如此反复遍历搜索整棵树,直到没有叶节点,它是一种递归算法。
时间复杂度
深度优先搜索的时间复杂度是指数级别的,它和节点数量成正比,比如节点数为N,则时间复杂度O(N)。
空间复杂度
由于深度优先搜索算法用栈来存储搜索路径,而栈的深度和节点的数量相同,因此空间复杂度也是O(N),和时间复杂度同样。
优点和缺点
深度优先搜索的优点是它能够搜索出一个最优解,并且实现很简单,它的缺点就是它非常容易进入死胡同,找不到最优解,另外时间和空间复杂度也是较高的。
示例代码
Python
def dfs(node, visited):
# 将节点加入到访问队列中
visited.add(node)
# 遍历其子节点
for n in node.children:
if n not in visited:
dfs(n, visited)
Java
使用Java来实现深度优先搜索算法,可以用下面的代码:
import java.util.LinkedList;
import java.util.Queue;
public class DFS {
private int V; // 节点数
private LinkedList<Integer> adj[]; // 邻接表
// 构造函数,初始化图
public DFS(int v) {
V = v;
adj = new LinkedList[v];
for (int i = 0; i < v; i++)
adj[i] = new LinkedList<>();
}
// 向图中添加边
public void addEdge(int v, int w) {
adj[v].add(w);
}
// 深度优先搜索实现
public void DFSUtil(int v, boolean visited[]) {
// 标记当前节点为已访问
visited[v] = true;
System.out.print(v + " ");
// 访问与v相连的所有节点
for (int i : adj[v]) {
if (!visited[i])
DFSUtil(i, visited);
}
}
// 调用DFSUtil函数
public void DFS(int v) {
// 默认所有节点都未访问
boolean visited[] = new boolean[V];
// 调用深度优先搜索实现
DFSUtil(v, visited);
}
public static void main(String args[]) {
DFS g = new DFS(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);
System.out.println("从节点 2 开始深度优先搜索: ");
g.DFS(2);
}
}
应用场景
深度优先搜索算法在图论中得到了广泛的应用,如拓扑排序、连通性检测,也可用于解决最短路径问题,以及解决迷宫问题,寻找旅行商问题等。
正面例子
深度优先搜索算法可以用来在节点间找到最短路径,也可以用它求解NP-hard问题,比如求解最小生成树(MST)。
反面例子
深度优先搜索算法容易落入死胡同,如果树中有大量的节点,那么时间和空间复杂度都会很高,而且非常容易导致内存溢出。